【问题标题】:C, socket programming: Connecting multiple clients to server using select()C、socket编程:使用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 似乎没有收到任何东西。谁能看到我哪里出错了?

【问题讨论】:

    标签: c sockets network-programming client select-function


    【解决方案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("--&gt;%.*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(选择的第三个参数)来完成。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-02-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-02-29
            • 1970-01-01
            相关资源
            最近更新 更多