C、socket编程:使用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(<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 似乎没有收到任何东西。谁能看到我哪里出错了?
I'm trying to make a server that can be connected to by multiple clients. Here's my code so far:
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] = '\0';
send(sock, message, 6, 0);
}
close(sock);
}
Server:
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;
}
As soon as a client connects and sends its first message, the server just runs in an infinite loop, and spits out garbage from the message array. recv doesn't seem to receive anything. Can anyone see where i go wrong?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
代码中有两个问题:
您应该执行
recv(i, ...)
而不是recv(clientsock[i], ...)
之后你不检查是否 < code>recv() 失败,因此
printf()
打印出未初始化的缓冲区message
,因此输出中出现垃圾Two issues in your code:
You should do
recv(i, ...)
instead ofrecv(clientsock[i], ...)
After that you do not check if
recv()
failed, and thereforeprintf()
prints out the uninitialised buffermessage
, hence the garbage in the output在调用 read 之前,您需要在读取循环中检查 limit <= 0。
You need to check for limit <= 0 in your read loop, before you call read.
在服务器的 while 循环中,将代码更改为执行
recv(i)
而不是recv(clientsocks[i])
。我已经实现了这段代码并且它适用于这个更改。In the while loop for the server, change the code to do
recv(i)
instead ofrecv(clientsocks[i])
. I have implemented this code and it works with this change.我用下面的替换了 else 并且它有效
I replaced the else with the below and it works
1)使用 PF_INET(协议族)而不是
是一个很好的做法
Socket 创建期间的 AF_INET(地址族)。
2) while(1) 循环内
每次建议使用 FD_ZERO(&readfds) 将 readfds 清空。
在recv()调用中你应该使用i而不是clientsocks[i]
你必须检查recv的返回值是否为负(这表明读取错误),如果是这种情况,你不必打印消息。
在打印消息期间,请确保 stdout/服务器已准备好向其中写入任何内容,您可以使用 writefds (select 的第三个参数)来执行此操作。
1) It is a good practice to use PF_INET(protocol family) rather than
AF_INET(address family) during the Socket creation .
2) within the while(1) loop
each time it is advisable to make your readfds empty by using FD_ZERO(&readfds).
in the recv() call you should use i rather than clientsocks[i]
you have to check return value of recv is negative(which indicating error in reading) if that is the case you do not have to print the message.
during printing the message make sure the stdout/server is ready for writing anything to it which you can do it by using writefds (3rd argument of select).