C、socket编程:使用select()将多个客户端连接到服务器
Posted
技术标签:
【中文标题】C、socket编程:使用select()将多个客户端连接到服务器【英文标题】:C, socket programming: Connecting multiple clients to server using select() 【发布时间】:2011-05-11 03:41:25 【问题描述】:我正在尝试制作一个可以由多个客户端连接的服务器。到目前为止,这是我的代码:
客户:
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);
服务器:
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;
一旦客户端连接并发送了它的第一条消息,服务器就会在无限循环中运行,并从消息数组中吐出垃圾。 recv 似乎没有收到任何东西。谁能看到我哪里出错了?
【问题讨论】:
【参考方案1】:您的代码中有两个问题:
你应该使用recv(i, ...)
而不是recv(clientsock[i], ...)
之后你不检查recv()
是否失败,因此printf()
打印出未初始化的缓冲区message
,因此输出中的垃圾
【讨论】:
【参考方案2】:您需要在读取循环中检查限制 在调用 read 之前。
【讨论】:
【参考方案3】:在服务器的 while 循环中,将代码更改为 recv(i)
而不是 recv(clientsocks[i])
。我已经实现了这段代码,它适用于这个变化。
【讨论】:
【参考方案4】:我用下面的替换了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);
【讨论】:
您不需要bzero()
。只需适当考虑recv() 的返回值,例如printf("-->%.*s\n", rval, buf);
。【参考方案5】:
1) 使用 PF_INET(协议族)而不是 Socket 创建期间的 AF_INET(address family)。
2) 在 while(1) 循环中 每次建议使用 FD_ZERO(&readfds) 使您的 readfds 为空。 在 recv() 调用中,您应该使用 i 而不是 clientsocks[i] 如果在这种情况下您不必打印消息,则必须检查 recv 的返回值是否为负(这表明读取错误)。 在打印消息期间,确保标准输出/服务器已准备好向其写入任何内容,您可以使用 writefds(选择的第三个参数)来完成。
【讨论】:
以上是关于C、socket编程:使用select()将多个客户端连接到服务器的主要内容,如果未能解决你的问题,请参考以下文章