C语言 C、socket编程:使用select()将多个客户端连接到服务器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4200172/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 07:05:26  来源:igfitidea点击:

C, socket programming: Connecting multiple clients to server using select()

csocketsnetwork-programmingclientselect-function

提问by ragnaroh

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] = '
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;
}
'; send(sock, message, 6, 0); } close(sock); }

Server:

服务器:

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

                }

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?

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

采纳答案by thkala

Two issues in your code:

您的代码中有两个问题:

  • You should do recv(i, ...)instead of recv(clientsock[i], ...)

  • After that you do not check if recv()failed, and therefore printf()prints out the uninitialised buffer message, hence the garbage in the output

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

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

回答by Chaitra Suresh

In the while loop for the server, change the code to do recv(i)instead of recv(clientsocks[i]). I have implemented this code and it works with this change.

在服务器的 while 循环中,将代码更改为 dorecv(i)而不是recv(clientsocks[i])。我已经实现了这段代码,它适用于这个变化。

回答by user207421

You need to check for limit <= 0 in your read loop, beforeyou call read.

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

回答by resultsway

I replaced the else with the below and it works

我用下面的替换了 else 并且它有效

##代码##

回答by Adarsh97

1) It is a good practice to use PF_INET(protocol family) rather than
AF_INET(address family) during the Socket creation .

1)
在 Socket 创建过程中使用 PF_INET(protocol family) 而不是AF_INET(address family)是一个很好的做法。

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).

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