2010-11-16 8 views
11

Ich versuche, einen Server zu machen, der von mehreren Clients verbunden werden kann. Hier ist mein Code so weit:C, Socket-Programmierung: Verbinden mehrerer Clients mit dem Server mit select()

Auftraggeber:

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

Sobald ein Client eine Verbindung und sendet seine erste Nachricht, die Server nur in einer Endlosschleife läuft, und spuckt den Müll aus dem Nachrichtenarray aus. recv scheint nichts zu empfangen. Kann jemand sehen, wo ich falsch liege?

Antwort

4

Zwei Probleme im Code:

  • Sie

  • Danach statt recv(clientsock[i], ...)

  • tun sollten Sie prüfen nicht, ob recv() nicht, und deshalb printf() druckt die uninitialised Puffer message, damit der Müll in der Ausgabe

1

Sie müssen auf < = 0 in Ihrer Leseschleife prüfen, vor Sie lesen lesen.

1

Ändern Sie in der while-Schleife für den Server den Code in recv(i) anstelle von recv(clientsocks[i]). Ich habe diesen Code implementiert und es funktioniert mit dieser Änderung.

0

ich das sonst mit der unten ersetzt und es funktioniert

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

       } 
+0

Sie brauchen nicht die 'bzero()'. Man berücksichtige den Rückgabewert von recv(), zum Beispiel in 'printf (" ->%. * S \ n ", rval, buf);'. – EJP

0

1) Es ist eine gute Praxis PF_INET (Protokollfamilie) statt
AF_INET (Adressfamilie) während der Socket-Erzeugung zu verwenden.

2) innerhalb der while (1) Schleife
jedes Mal ist es ratsam, Ihre readfds leer unter Verwendung FD_ZERO (& readfds) zu machen. in der recv() -Aufruf sollten Sie i anstelle von clientsocks [i] verwenden Sie müssen überprüfen, Rückgabewert von recv ist negativ (was angibt, Fehler beim Lesen), wenn dies der Fall ist, müssen Sie die Nachricht nicht drucken. Während des Druckens der Nachricht vergewissern Sie sich, dass der stdout/server bereit ist, etwas zu schreiben, was Sie mit writefds (3. Argument von select) tun können.

Verwandte Themen