2016-04-30 5 views
0

Ich bin neu, Socket-Programmierung, aber ich habe gefolgt ibm Beispiel https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/rzab6/poll.htm und einige Code geändert, um es besser zu machen, aber wenn ich den Server über Telnet-Port verbinden, und mach es echo messages funktioniert es für den ersten Client, der verbindet, aber zweitens nicht die Nachrichten Echo?poll() Socket-Programmierung tcp linux mehrere Verbindungen Problem

#include <netinet/in.h> // sockaddr_in struct 
#include <arpa/inet.h> //inet_addr() 
#include <sys/socket.h> 
#include <errno.h> //errors 
#include <stdio.h> //perror() 
#include <cstdlib> //EXIT_FAILURE 
#include <sys/ioctl.h> //FIONBIO 
#include <unistd.h> //close file descriptor 
#include <fcntl.h> //make non blocking 
#include <poll.h> //poll stuff 
#include <string.h> //memset 
int main() 
{ 
    int s = -1; 
    int rc; 
    int optval = 1; 
    int timeout; 
    bool end_server = false; //because we need to log if EWOULDBLOCK is true... 

    struct pollfd fds[200]; //initialize pollfd struct 
    int nfds = 1; // nfds_t really set to 1 else it will be 199 once we pass it to poll.... 

    int current_size = 0; 

    int new_s = -1; 

    int close_conn; 

    char *buff; 

    int len; 

    bool compress_array; 

    s = socket(AF_INET, SOCK_STREAM, 0); 

    //make socket description reusable with SO_REUSEADDR 
    rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&optval), sizeof(optval)); 
    if(rc < 0){ 
     perror("setsockopt()"); 
     close(s); 
     exit(EXIT_FAILURE); 
    } 

    //make socket non-blocking 
    //rc = ioctl(s, FIONBIO, reinterpret_cast<char*>(&optval)); 
    //if(rc < 0) 
    //{ 
    // perror("ioctl()"); 
    // close(s); 
    // exit(EXIT_FAILURE); 
    //} 
    fcntl(s, F_SETFL, O_NONBLOCK); 

    struct sockaddr_in saddr; 
    //initialize sockaddr_in struct 
    memset(&saddr, 0, sizeof(saddr)); 

    saddr.sin_family = AF_INET; 
    saddr.sin_port = htons(80); 
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 

    rc = bind(s, reinterpret_cast<struct sockaddr *>(&saddr), sizeof(saddr)); 

    if(rc < 0){ 
     perror("bind()"); 
     exit(EXIT_FAILURE); 
    } 

    rc = listen(s, 32); 
    if(rc < 0){ 
     perror("listen() failed"); 
     close(s); 
     exit(EXIT_FAILURE); 
    } 

    //initialize fds struct 
    memset(&fds, 0, sizeof(fds)); 

    fds[0].fd = s; 
    fds[0].events = POLLIN; //check if data to read 

    //initialize timeout value to 3 mins based on millisecs 
    //timeout = (3 * 60 * 1000); // because function will be like sleep() that uses millisecs 
    timeout = 10000; 

    do{ 
     //call poll() and wait 3 mins to complete because of timeout 
     printf("Waiting on poll()...\n"); 
     rc = poll(fds, nfds, timeout); 

     if(rc < 0){ 
      perror("poll() failed"); 
      exit(EXIT_FAILURE); 
     } 

     //check if 3 minutes timeout expired 
     if(rc == 0){ 
      printf("poll() timed out ending program...\n"); 
      exit(EXIT_FAILURE); 
     } 

     current_size = nfds; 
     for(int i = 0; i < current_size; i++) 
     { 
      //loop thru fds and check if revents returns POLLIN, means the fd have data to read... 
      if(fds[i].revents == 0) 
       continue; 


      //if revents is not POLLIN then exit program and log 
      if(fds[i].revents != POLLIN){ 
       printf("revents != POLLIN, revents = %d\n", fds[i].revents); 
       //end_server = true; 
       //break; 
       //perror("revents unknown"); 
       //exit(EXIT_FAILURE); 
       close(fds[i].fd); 
       fds[i].fd = -1; 
       break; 
      } 

      if(fds[i].fd == s){ 
       printf("Listening socket available\n"); 

       do{ 
        //accept each new incoming connections 
        new_s = accept(s, NULL, NULL); 
        if(new_s < 0){ 
         if(errno != EWOULDBLOCK){ 
          perror("accept() failed because of socket would block"); 
          end_server = true; 
         } 
         //printf("something else wrong with accept()\n"); 
         break; 
        } 

        //add new incoming connection 
        printf("new incoming connection - nfds: %d\n", new_s); 
        fds[nfds].fd = new_s; 
        fds[nfds].events = POLLIN; 
        nfds++; 
        //continue; 
        //loop back up and accept another connection 

       } while(new_s != -1); 
      } 
      // file descriptor is readable because its now new_s instead of s 
      else { 
       printf("descriptor %d is readable\n", fds[i].fd); 
       close_conn = false; 
       //receive all data on this connection till we go back and poll again 
       do { 

        rc = recv(fds[i].fd, reinterpret_cast<void*>(&buff), sizeof(buff), 0); 
        if(rc < 0){ 
         if(errno != EWOULDBLOCK){ 
          perror("recv() failed"); 
          close_conn = true; 
         } 
         break; 
        } 

        //check if conn was closed by client 
        if(rc == 0){ 
         printf("connection closed"); 
         close_conn = true; 
         break; 
        } 

        //data was received 
        len = rc; 
        printf("%d bytes received", len); 

        //process stuff or echo data back to client 
        rc = send(fds[i].fd, reinterpret_cast<void*>(&buff), sizeof(buff), 0); 
        if(rc < 0){ 
         perror("send() failed"); 
         close_conn = true; 
         break; 
        } 
        memset(&buff, 0, sizeof(buff)); 

       } while (true); 
       if(close_conn){ 
        close(fds[i].fd); 
        fds[i].fd = -1; 
        compress_array = true; 
       } 

      } 


     } 
     if(compress_array){ 
      compress_array = false; 
      int i = 0; 
      for(i = 0; i < nfds; i++){ 
       if(fds[i].fd == -1){ 
        for(int j = i; j < nfds; j++){ 
         fds[j].fd = fds[j+1].fd; 
        } 
        i--; 
        nfds--; 
       } 
      } 
     } 

    } while (end_server == false); 

    //clean all sockets that are open 
    for(int i = 0; i < nfds; i++){ 
     if(fds[i].fd > 0){ // if already -1 don't need to close socket 
      close(fds[i].fd); 
      fds[i].fd = -1; 
     } 
    } 



    return 0; 
} 
+0

aber es funktioniert, wenn ich den ersten Client trenne und versuche, auf einem anderen zu senden? –

+0

gefunden, was es verursacht es ist, weil ich Pause hinzugefügt habe; nach printf ("etwas anderes stimmt nicht mit accept() \ n"); aber jetzt, wenn ich eine Verbindung mit dem ersten Client sende msg es echo zurück, aber wenn ich eine Verbindung mit dem zweiten Client und senden msg und trennen von der ersten Client sendet es nur Echo zurück, wenn die erste Verbindung trennt? Wie man es so macht, dass es zur gleichen Zeit anstatt der Warteschlange sendet? –

+0

Ich weiß, die Warteschlange ist wegen RC = listen (s, 32); aber wie man es nicht blockierend macht? –

Antwort

0

Ahh, es war, weil ich mit while (true) geschlungen, so dass es immer wieder versucht, Looping Daten empf stattdessen wieder nach oben zu gehen und neue Verbindung zu der Liste hinzufügen.

Verwandte Themen