我正在检查由stackoverflow成员 atanos 编写的关于在2010年将多个客户端连接到单个服务器的程序,我修改了他的程序以接受来自命令行的连接细节,下面是服务器和客户代码。
Server.c
int main(int argc, char **argv)
{
fd_set fds, readfds;
int i, clientaddrlen, portno;
int clientsock[2], rc, numsocks = 0, maxsocks = 2;
if (argc < 2){
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
int serversock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serversock == -1) perror("Socket");
portno = atoi(argv[1]);
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(portno);
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");
else printf("Connection accepted\n");
FD_SET(clientsock[numsocks], &fds);
numsocks++;
}
else
printf("Ran out of socket space.\n");
}
else
{
int messageLength = 10;
char message[messageLength+1];
int numOfChRead, index = 0, limit = messageLength+1;
numOfChRead = recv(clientsock[i], message, messageLength,0);
if(numOfChRead > 0)
printf("Data Received !!! length: %d Message: %s", numOfChRead, message);
else
printf("Nothing read\n");
}
}
}
}
close(serversock);
return 0;
}
Client.c
int main(int argc, char **argv)
{
struct sockaddr_in servaddr;
struct hostent *server;
int portno, bytesSent = 0;
if (argc < 3){
fprintf(stderr,"Usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == -1) perror("Socket");
server = gethostbyname(argv[1]);
if (server == NULL){
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((void *) &servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(portno);
bcopy((char *)server->h_addr,(char *)&servaddr.sin_addr.s_addr,server->h_length);
if (-1 == connect(sock, (struct sockaddr *)&servaddr, sizeof(servaddr))) perror("Connect");
while(1) {
char message[10];
fgets(message, 10, stdin);
message[10] = '\0';
bytesSent = send(sock, message, strlen(message), 0);
if(bytesSent == -1) printf("Sending failed with errno %d", errno);
else printf("Sent %d characters", bytesSent);
}
close(sock);
}
我可以看到服务器接受多个连接但是当我从任何客户端发送消息时,服务器中的recv API不会读取任何内容。客户端的发送API成功,我可以看到所有字符都已发送。有人可以发表评论吗?
答案 0 :(得分:2)
问题是,您实际上从未将客户端连接置于读取fd_set
。
该行:
readfds = fds;
将readfds
重置为仅包含服务器(侦听)套接字的状态。您需要在调用fd_set
之前完全重新设置select
中的每个客户端文件描述符,每次都在循环中。
可能是其他问题(需要经过很多代码),但这似乎是最有可能发生的问题。
(顺便说一句,我不确定作业是否合法。我不认为实施要求fd_set
是简单的,可复制的结构。)
答案 1 :(得分:1)
您的代码中存在多个错误。您没有正确使用选择呼叫。 select的第一个参数占用你正在监听的最多fds加1.而第二个参数包含要监视的fds列表。
我用fdmax替换了你的FD_SETSIZE。我更正了代码中的问题并粘贴在下面。
8 int main(int argc, char **argv)
9 {
10 fd_set fds, readfds;
11 int i, clientaddrlen, portno;
12 int clientsock[2], rc, numsocks = 0, maxsocks = 2;
13 int fdmax=0;
14
15 if (argc < 2){
16 fprintf(stderr,"ERROR, no port provided\n");
17 exit(1);
18 }
19
20 int serversock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
21
22 if (serversock == -1) perror("Socket");
23
24 portno = atoi(argv[1]);
25 struct sockaddr_in serveraddr, clientaddr;
26 bzero(&serveraddr, sizeof(struct sockaddr_in));
27 serveraddr.sin_family = AF_INET;
28 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
29 serveraddr.sin_port = htons(portno);
30
31 if (-1 == bind(serversock, (struct sockaddr *)&serveraddr,sizeof(struct sockaddr_in))) perror("Bind");
32
33 if (-1 == listen(serversock, SOMAXCONN)) perror("Listen");
34
35 FD_ZERO(&fds);
36 FD_SET(serversock, &fds);
37 fdmax = serversock;
38
39 clientaddrlen = sizeof(clientaddr);
40 while(1) {
41 readfds = fds;
42 rc = select(fdmax + 1, &readfds, NULL, NULL, NULL);
43
44 if (rc == -1){
45 perror("Select");
46 break;
47 }
48
49 for (i = serversock; i <= fdmax; i++)
50 {
51 if (FD_ISSET(i, &readfds)){
52 if (i == serversock){
53 if (numsocks < maxsocks){
54 clientsock[numsocks] = accept(serversock,(struct sockaddr *) &clientaddr,
55 (socklen_t *)&clientaddrlen);
56
57 if (clientsock[numsocks] == -1) perror("Accept");
58 else printf("Connection accepted\n");
59
60 FD_SET(clientsock[numsocks], &fds);
61 fdmax = clientsock[numsocks];
62 numsocks++;
63 }
64 else
65 printf("Ran out of socket space.\n");
66 }
67 else
68 {
69 int messageLength = 100;
70 char message[messageLength+1];
71 int numOfChRead, index = 0, limit = messageLength+1;
72
73 numOfChRead = recv(i, message, messageLength,0);
74
75 if(numOfChRead > 0)
76 printf("Data Received !!! length: %d Message: %s", numOfChRead, message);
77 else
78 printf("Nothing read\n");
79 }
80 }
81 }
82 }
83 close(serversock);
84 return 0;
85 }