C, программирование сокетов: подключение нескольких клиентов к серверу с помощью select () - PullRequest
13 голосов
/ 17 ноября 2010

Я пытаюсь создать сервер, к которому могут подключаться несколько клиентов.Вот мой код:

Клиент:

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 голосов
/ 17 ноября 2010

Две проблемы в вашем коде:

  • Вы должны сделать recv(i, ...) вместо recv(clientsock[i], ...)

  • После этого вы не проверяете, произошел ли сбой recv(), и поэтому printf() печатает неинициализированный буфер message, следовательно, мусор в выводе

1 голос
/ 26 сентября 2012

В цикле while для сервера измените код на recv(i) вместо recv(clientsocks[i]).Я реализовал этот код, и он работает с этим изменением.

1 голос
/ 17 ноября 2010

Вам необходимо проверить ограничение <= 0 в цикле чтения, <em>до того, как вы вызовете чтение.

0 голосов
/ 09 февраля 2018

1) Рекомендуется использовать PF_INET (семейство протоколов), а не
AF_INET (семейство адресов) при создании Socket.

2) в цикле while (1)
каждый раз желательно сделать ваши readfds пустыми, используя FD_ZERO (& readfds). в вызове recv () вы должны использовать i, а не clientocks [i] Вы должны проверить, что возвращаемое значение recv является отрицательным (что указывает на ошибку при чтении), если в этом случае вам не нужно печатать сообщение. во время печати сообщения убедитесь, что стандартный вывод / сервер готов к записи в него всего, что вы можете сделать, используя writefds (третий аргумент выбора).

0 голосов
/ 26 марта 2013

Я заменил остальное на ниже, и это работает

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

                }
...