C, programmation de socket: Connecter plusieurs clients au serveur en utilisant select ()
Je suis en train de faire un serveur qui peut être connecté à plusieurs clients. Voici mon code pour l'instant:
Client:
int main(int argc, char **argv) {
struct sockaddr_in servaddr;
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == -1) perror("Socket");
bzero((void *) &servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(6782);
servaddr.sin_addr.s_addr = inet_addr(<server_ip_address>);
if (-1 == connect(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)))
perror("Connect");
while(1) {
char message[6];
fgets(message, 6, stdin);
message[5] = 'int main(int argc, char **argv) {
struct sockaddr_in servaddr;
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == -1) perror("Socket");
bzero((void *) &servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(6782);
servaddr.sin_addr.s_addr = inet_addr(<server_ip_address>);
if (-1 == connect(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)))
perror("Connect");
while(1) {
char message[6];
fgets(message, 6, stdin);
message[5] = '\0';
send(sock, message, 6, 0);
}
close(sock);
}
';
send(sock, message, 6, 0);
}
close(sock);
}
Serveur:
int main(int argc, char **argv) {
fd_set fds, readfds;
int i, clientaddrlen;
int clientsock[2], rc, numsocks = 0, maxsocks = 2;
int serversock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serversock == -1) perror("Socket");
struct sockaddr_in serveraddr, clientaddr;
bzero(&serveraddr, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(6782);
if (-1 == bind(serversock, (struct sockaddr *)&serveraddr,
sizeof(struct sockaddr_in)))
perror("Bind");
if (-1 == listen(serversock, SOMAXCONN))
perror("Listen");
FD_ZERO(&fds);
FD_SET(serversock, &fds);
while(1) {
readfds = fds;
rc = select(FD_SETSIZE, &readfds, NULL, NULL, NULL);
if (rc == -1) {
perror("Select");
break;
}
for (i = 0; i < FD_SETSIZE; i++) {
if (FD_ISSET(i, &readfds)) {
if (i == serversock) {
if (numsocks < maxsocks) {
clientsock[numsocks] = accept(serversock,
(struct sockaddr *) &clientaddr,
(socklen_t *)&clientaddrlen);
if (clientsock[numsocks] == -1) perror("Accept");
FD_SET(clientsock[numsocks], &fds);
numsocks++;
} else {
printf("Ran out of socket space.\n");
}
} else {
int messageLength = 5;
char message[messageLength+1];
int in, index = 0, limit = messageLength+1;
while ((in = recv(clientsock[i], &message[index], limit, 0)) > 0) {
index += in;
limit -= in;
}
printf("%d\n", index);
printf("%s\n", message);
}
}
}
}
close(serversock);
return 0;
}
Dès qu'un client se connecte et envoie son premier message, le serveur s'exécute dans une boucle infinie, et crache des ordures à partir du message de tableau. recv ne semble pas recevoir quoi que ce soit. Quelqu'un peut-il voir où suis-je trompé?
source d'informationauteur ragnaroh
Vous devez vous connecter pour publier un commentaire.
Deux questions dans votre code:
Que vous devriez faire
recv(i, ...)
au lieu derecv(clientsock[i], ...)
Après que vous ne cochez pas si
recv()
échoué, et doncprintf()
imprime le non initialisée tamponmessage
donc les ordures dans la sortieVous avez besoin pour vérifier la limite de <= 0 dans votre lecture de la boucle, avant vous appelez lire.
Dans la boucle while pour le serveur, modifier le code pour faire
recv(i)
au lieu derecv(clientsocks[i])
. J'ai mis en œuvre ce code et il fonctionne avec ce changement.J'ai remplacé l'autre avec le ci-dessous et il fonctionne
1) C'est une bonne pratique d'utiliser PF_INET(protocole de famille) plutôt que d'
AF_INET(adresse de la famille) lors de la création de la Socket .
2) dans le while(1) de la boucle
chaque fois, il est conseillé de faire votre readfds vide en utilisant FD_ZERO(&readfds).
dans l'appel recv (), vous devriez utiliser j'ai plutôt que clientsocks[i]
vous avez pour vérifier la valeur de retour de recv est négatif(ce qui indique erreur dans la lecture), si c'est le cas, vous n'avez pas à imprimer le message.
lors de l'impression, le message assurez-vous que le stdout/serveur est prêt pour écrire quoi que ce soit qui vous pouvez le faire en utilisant writefds (3ème argument de sélection).