代码之家  ›  专栏  ›  技术社区  ›  ragnaroh

C,socket编程:使用select()将多个客户机连接到服务器

  •  13
  • ragnaroh  · 技术社区  · 15 年前

    我正在尝试创建一个可以由多个客户机连接的服务器。到目前为止,我的代码是:

    客户:

    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似乎没有收到任何东西。有人知道我哪里出错了吗?

    5 回复  |  直到 15 年前
        1
  •  4
  •   user207421    11 年前

    代码中有两个问题:

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

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

        2
  •  1
  •   user207421    15 年前

    您需要在读取循环中检查极限<=0, 之前 你叫读。

        3
  •  1
  •   Marijn    13 年前

    在服务器的while循环中,将代码更改为do recv(i) 而不是 recv(clientsocks[i]) . 我已经实现了这个代码,它与这个更改一起工作。

        4
  •  0
  •   resultsway    13 年前

    我把其他的换成下面的,它就工作了

     } 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);
    
                    }
    
        5
  •  0
  •   Adarsh97    8 年前

    1)使用pf inet(协议系列)而不是
    套接字创建期间的af-inet(地址族)。

    2)在while(1)循环内
    每次建议使用fd_0(&readfds)清空readfds。 在recv()调用中,您应该使用i而不是clientsocks[i] 如果不需要打印消息,则必须检查recv的返回值是否为负值(表示读取错误)。 在打印消息的过程中,请确保stdout/server已准备好写入任何可以使用writefds(select的第三个参数)进行写入的内容。

    推荐文章