C, socket programming: Connecting multiple clients

2019-03-11 09:44发布

问题:

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] = '\0';

    send(sock, message, 6, 0);
  }


  close(sock);
}

Server:

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

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?

回答1:

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



回答2:

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



回答3:

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.



回答4:

I replaced the else with the below and it works

 } 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:

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

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