C,套接字编程:使用select()将多个客户端连接到服务器

我正在尝试制作一个可以由多个客户端连接的服务器。 到目前为止,这是我的代码:

客户:

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(); 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); } 

服务器:

 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  0) { index += in; limit -= in; } printf("%d\n", index); printf("%s\n", message); } } } } close(serversock); return 0; } 

一旦客户端连接并发送其第一条消息,服务器就会在无限循环中运行,并从消息数组中吐出垃圾。 recv似乎没有收到任何东西。 任何人都可以看到我哪里出错了?

您的代码中有两个问题:

  • 你应该做recv(i, ...)而不是recv(clientsock[i], ...)

  • 之后你不检查recv()失败,因此printf()打印出未初始化的缓冲区message ,因此输出中的垃圾

调用read 之前 ,需要在读取循环中检查限制<= 0。

在服务器的while循环中,将代码更改为recv(i)而不是recv(clientsocks[i]) 。 我已实现此代码,它适用于此更改。

我用下面替换了else,它可以工作

  } else { /* int messageLength = 5; char message[messageLength+1]; int in, index = 0, limit = messageLength+1; memset ( &message[index] , 0, sizeof ( message [index] ) ); while ((in = recv(i, &message[index], limit, 0)) > 0) { index += in; limit -= in; } printf("%d\n", index); printf("%s\n", message); */ bzero(buf, sizeof(buf)); if ((rval = read(i, buf, 1024)) < 0) perror("reading stream message"); else if (rval == 0) printf("Ending connection\n"); else printf("-->%s\n", buf); } 

1)使用PF_INET(协议族)而不是使用PF_INET是一种好习惯
创建套接字期间的AF_INET(地址族)。

2)while(1)循环内
每次建议使用FD_ZERO(&readfds)使readfds为空。 在recv()调用中你应该使用i而不是clientsocks [i]你必须检查recv的返回值是否定(这表示读取错误),如果是这种情况你不必打印消息。 在打印消息期间,请确保stdout / server已准备好向其写入任何内容,您可以使用writefds(select的第3个参数)来执行此操作。