C语言,套接字编程:使用select()连接多个客户端到服务器

13
我想制作一个可以被多个客户端连接的服务器。以下是我的代码:
客户端:
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个回答

4

您的代码存在两个问题:

  • 您应该使用recv(i, ...)而不是recv(clientsock[i], ...)

  • 之后,您没有检查recv()是否失败,因此printf()打印未初始化的缓冲区message,导致输出中出现垃圾信息。


1

在调用read之前,你需要在读取循环中检查limit是否小于等于0。


1
在服务器的 while 循环中,将代码更改为执行 recv(i) 而不是 recv(clientsocks[i])。我已经实现了这个更改,并且它可以正常工作。

0

1)在套接字创建时,最好使用PF_INET(协议族)而不是AF_INET(地址族)。

2)在while(1)循环内,每次建议使用FD_ZERO(&readfds)使您的readfds为空。 在recv()调用中,应使用i而不是clientsocks [i]。 您必须检查recv的返回值是否为负数(表示读取错误),如果是这种情况,则无需打印消息。 在打印消息时,请确保stdout / server准备好写入任何内容,您可以通过使用select的writefds(第3个参数)来实现它。


0

我用下面的代码替换了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("-->%.*s\n", rval, buf); 中。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接