Programmation Socket: UDP Client-Serveur en C
Je suis en train d'écrire un serveur de client de programme en utilisant UDP, et d'attendre-et-stop, mais je n'ai pas à cette partie, je suis encore à essayer de comprendre comment les deux processus (client et serveur) communiquer, parce que sur mon programme client, l'utilisateur doit entrer le nom du serveur ou adresse IP et un nom de port, puis envoyer une expression que le serveur doit calculer. Cependant, j'ai creusé quelques tutoriels sur internet et après codage en conséquence (ou je le croyais) que je ne peux pas faire que le client communique avec le serveur. Ci-dessous mon code, merci de m'éclairer ce que je fais mal, si c'est le bind()
, sendto()
, recvfrom()
ou socket()
, ou la totalité d'entre eux. Je ne vois pas quel est exactement le problème. Je sais que le côté client ne faut pas courir sur une boucle infinie, mais jusqu'à présent, je veux faire les programmes de communiquer les uns avec les autres, par la suite, je vais polonais de mon code. Merci!
code côté client:
#include <stdio.h> //Default System Calls
#include <stdlib.h> //Needed for OS X
#include <string.h> //Needed for Strlen
#include <sys/socket.h> //Needed for socket creating and binding
#include <netinet/in.h> //Needed to use struct sockaddr_in
#include <time.h> //To control the timeout mechanism
#define EXPR_SIZE 1024
#define BUFLEN 512
#define TRUE 1
#define FALSE 0
#define SERVERLEN 1024
int main(int argc, char **argv){
long portNum; //Since it's possible to input a value bigger
//than 65535 we'll be using long to
//avoid overflows
char expr[EXPR_SIZE];
char server[SERVERLEN];
int fd; //file descriptor for the connected socket
int buf[512];
struct hostent *h; //information of the host
unsigned int addrLen; //address length after getting the port number
struct sockaddr_in myaddr; //address of the client
struct sockaddr_in servaddr; //server's address
unsigned int exprLen;
socklen_t slen = sizeof(servaddr);
printf("Enter server name or IP address:");
scanf("%s",server);
printf("Enter port:");
scanf("%ld",&portNum);
if ((portNum < 0) || (portNum > 65535)) {
printf("Invalid port number. Terminating.");
return 0;
}
printf("Enter expression:");
scanf("%s",expr);
if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
perror("cannot create socket");
return 0;
}
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(0);
if(bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0){
perror("cannot bind");
return 0;
}
/*
//Discovering the port number the OS allocated
addrLen = sizeof(myaddr);
if(getsockname(fd, (struct sockaddr *)&myaddr, &addrLen) < 0){
perror("cannot getsockname");
return 0;
}
printf("local port number = %d\n", ntohs(myaddr.sin_port));
*/
memset((char*)&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htonl(portNum);
exprLen = sizeof(expr);
while(TRUE){
printf("Sending message to %s port %ld\n",server, portNum);
if (sendto(fd, expr, strlen(expr), 0, (struct sockaddr *)&servaddr, slen) < 0) {
perror("cannot sendto()");
}
printf("Success\n");
}
return 0;
}
Code côté serveur:
#include <stdio.h> //Default System Calls
#include <stdlib.h> //Needed for OS X
#include <string.h> //Needed for Strlen
#include <sys/socket.h> //Needed for socket creating and binding
#include <netinet/in.h> //Needed to use struct sockaddr_in
#include <time.h> //To control the timeout mechanism
#define EXPR_SIZE 1024
#define BUFLEN 512
#define TRUE 1
#define SERVERLEN 1024
int main(int argc, char **argv){
struct sockaddr_in myaddr; //address of the server
struct sockaddr_in claddr; //address of the client
char buf[BUFLEN];
int fd;
long recvlen;
socklen_t clientlen;
if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
perror("cannot create socket");
return 0;
}
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(0);
if(bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0){
perror("cannot bind");
return 0;
}
clientlen = sizeof(claddr);
while (TRUE) {
recvlen = recvfrom(fd, buf, BUFLEN, 0, (struct sockaddr *)&claddr, &clientlen);
if (recvlen < 0) {
perror("cannot recvfrom()");
return 0;
}
printf("Received %ld bytes\n",recvlen);
buf[recvlen] = 0;
printf("Received message: \"%s\"\n",buf);
}
return 0;
}
Le programme serveur n'a pas de sortie de rien, tandis que le client sorties jusqu'à ce que le processus est interrompu:
Enter server name or IP address:127.0.0.1
Enter port:30
Enter expression:2+2
Sending message to 127.0.0.1 port 30
cannot sendto(): Can't assign requested address
J'ai essayé de changer le nom de serveur est localhost, et d'autres ports, mais en vain.
Votre client doit envoyer le même port que le serveur lié.
pour cette ligne de client:
scanf("%s",server);
il n'y a pas de nombre maximum de caractères d'entrée modificateur sur le "%s " spécificateur de format. Par conséquent, l'utilisateur peut de dépassement de la mémoire tampon d'entrée, résultant en un comportement indéterminé et peut conduire à une seg fault événement. Suggérer: scanf("%1023s",server);
la compilation du logiciel client les résultats dans plusieurs des messages d'avertissement sur les paramètres inutilisés inutilisés variable, jeu de variables, mais pas utilisé, etc. Un bon départ sur la fixation de toutes ces mises en garde serait de remplacer la fonction main() signature avec
int main( void )
lors de l'appel de la plupart des fonctions du système, par exemple
scanf()
, toujours vérifier la valeur retournée (pas la valeur du paramètre) pour assurer l'opération a été un succès.
OriginalL'auteur William Studart | 2016-02-23
Vous devez vous connecter pour publier un commentaire.
Lors de l'élaboration de logiciels de réseau (en particulier lors de l'utilisation de la BSD socket interface), il est important de garder les choses aussi simples que possible jusqu'à ce que vous avez établi la communication de base. Ensuite, vous pouvez progressivement ajouter des fonctionnalités, tout en s'assurant que vous ne cassez rien, le long de la voie.
Sur le côté client, en gardant les choses simples moyens
Ne pas appeler
bind
dans le client. Le système d'exploitation sera de choisir une interface appropriée et d'attribuer un numéro de port aléatoire, donc il n'y a pas besoin debind
la prise.Utilisation codé en dur l'adresse du serveur (par exemple l'adresse 127.0.0.1). L'adresse 127.0.0.1 (0x7f000001) est l'adresse d'hôte local, adapté à l'envoi de paquets de données à un serveur sur la même machine.
Utiliser un hard-codés numéro de port (par exemple, 50037). Éphémère numéros de port doit être supérieure à 0xC000 hex (49152 décimal).
Utiliser un message codé en dur, par exemple "bonjour".
Avec cela à l'esprit, voici ce que le logiciel client ressemble
Sur le côté serveur, garder les choses simples moyens
INADDR_ANY
, c'est à dire laisser le système d'exploitation choisir une interface appropriée.recvfrom
, c'est à dire passerNULL, 0
que les deux derniers paramètres.Avec cela à l'esprit, voici ce que le logiciel du serveur ressemble
OriginalL'auteur user3386109