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个参数)来执行此操作。