2011-10-22 19 views
0

Я работаю над клиентской серверной программой, которая использует вызовы select() для прослушивания нескольких сокетов. Но мой выбранный вызов блокируется, хотя у меня есть сообщение в одном из этих сокетов, select() вызов не распознает его, и он все еще ждет там неопределенно.C сокеты - Заблокировано при выборе

В программе есть 2 объекта, мастер и клиент. Мастер знает, сколько клиентов он будет обрабатывать и ждет, чтобы клиенты подключились к нему. После получения подтверждения клиента он сохраняет свою информацию. Как только все клиенты подключены, он затем отправляет информацию своего соседнего клиента каждому клиенту, чтобы он мог создать сеть. Именно здесь я использую select() для наблюдения за множеством сокетов, master имеет сокет для каждого дочернего tat, подключенного к нему клиент имеет 3 основных разъема s1-говорить с мастером s2-ребенок прослушивает подключение к этому socket соседка-сокет, на котором его сосед ждет соединения. (то есть S2 в соседнем) p- сокет, являющийся результатом соединения со своего соседа (accept s2 - возвращает ths) Я использую select для прослушивания сервер, собственный сокет для входящих подключений и один раз.

Первоначально мой сервер отправляет строку «привет» одному из клиентов, который получает это сообщение и передает его соседнему, таким образом, когда строка возвращается к первому ребенку, который получил это сообщение с сервера , он передает его своему соседу. Но все, хотя все дочерние элементы находятся в select(), ждут ввода. Что может вызвать это?

void main(int argc, char **argv) { 

    int s1, s2, n, server_port, sc1, sc2, rv, rc, left_peer_port; 
    int peer_port; 
    fd_set writefds, readfds; 
    struct timeval tv; 
    struct hostent *server_info, *child_info, *left_peer_info; 
    int start_flag = 0; 

    struct sockaddr_in server, peer, incoming; 

    char host_child[64]; 
    char *left_host = malloc(1); 
    char *right_host = malloc(1); 
    char buf1[256]; 
    char buf2[256]; 

    server_port = atoi(argv[2]); 

    //speak to peer using this 
    s2 = socket(AF_INET, SOCK_STREAM, 0); 
    if (s2 < 0) { 
     perror("socket:"); 
     exit(s2); 
    } 

    peer_port = server_port + 1; 

    gethostname(host_child, sizeof host_child); 

    child_info = gethostbyname(host_child); 

    if (child_info == NULL) { 
     fprintf(stderr, "%s: host not found (%s)\n", argv[0], host_child); 
     exit(1); 
    } 


    peer.sin_family = AF_INET; 
    memcpy(&peer.sin_addr, child_info->h_addr_list[0], child_info->h_length); 
    int changeport = 0; 
    do { 
     peer.sin_port = htons(peer_port); 
     rc = bind(s2, (struct sockaddr *) &peer, sizeof(peer)); 

     if (rc < 0) { 
      //perror("bind:"); 
      peer_port++; 
      changeport = 1; 
      //exit(rc); 

     } else { 
      changeport = 0; 
     } 

    } while (changeport == 1); 

    if (listen(s2, 100) == -1) { 
     perror("listen"); 
     exit(3); 
    } 



//Now talk to server 

    server_info = gethostbyname(argv[1]); 

    if (server_info == NULL) { 
     fprintf(stderr, "%s: host not found\n", argv[0]); 
     exit(1); 
    } 


// pretend we've connected both to a server at this point 
//speak to server using this 
    s1 = socket(AF_INET, SOCK_STREAM, 0); 
    if (s1 < 0) { 
     perror("socket:"); 
     exit(s1); 
    } 


    server.sin_family = AF_INET; 
    server.sin_port = htons(server_port); 
    memcpy(&server.sin_addr, server_info->h_addr_list[0], server_info->h_length); 

//To talk to the server 

    sc1 = connect(s1, (struct sockaddr *) &server, sizeof(server)); 
    if (sc1 < 0) { 
     perror("connect:"); 
     exit(sc1); 
    } 

    int send_len; 
    char *str = malloc(1); 
    sprintf(str, "%d", peer_port); 
    printf("\nport-here=%s\n", str); 


    send_len = send(s1, str, strlen(str), 0); 
    if (send_len != strlen(str)) { 
     perror("send"); 
     exit(1); 
    } 

    int recv_len; 
    char buf[100]; 
    int ref = 0; 
    int recv_stage = 0; 
    int start_id; 


    recv_len = recv(s1, buf, 34, 0); 
    if (recv_len < 0) { 
     perror("recv"); 
     exit(1); 
    } 
    buf[recv_len] = '\0'; 
    char *temp_port; 

    if (!strcmp("close", buf)) 
     printf("%s", buf); 
      //break; 
    else { 
     char *temp_buffer = malloc(1); 
     char *id = malloc(100); 
     char *pp = malloc(1); 
     strcpy(temp_buffer, buf); 

     char *search = ":"; 
     temp_port = strtok(temp_buffer, search); 
     strcpy(buf, temp_port); 
     printf("temp_name%s", temp_port); 

     temp_port = strtok(NULL, search); 
     strcpy(pp, temp_port); 
     printf("temp_port%s", temp_port); 
     temp_port = strtok(NULL, search); 
     strcpy(id, temp_port); 
     printf("id%s", temp_port); 

     strcpy(temp_port, pp); 
     printf("\nbuf=%s\n", buf); 
     printf("\nport=%s\n", temp_port); 
     printf("\nid=%s\n", id); 
     start_id = atoi(id); 
    } 

//To send packet to its neighbour 
    left_peer_info = gethostbyname(buf); 
    printf("\nleft host=%s\n", buf); 
    if (left_peer_info == NULL) { 
     fprintf(stderr, "%s: host not found\n", left_host); 
     exit(1); 
    } 
    left_peer_port = atoi(temp_port); 


    int neighbour_socket; 
    struct hostent *neighbour_info; 
    struct sockaddr_in neighbour; 
    neighbour_socket = socket(AF_INET, SOCK_STREAM, 0); 
    if (neighbour_socket < 0) { 
     perror("socket:"); 
     exit(neighbour_socket); 
    } 

    neighbour_info = left_peer_info; 


    neighbour.sin_family = AF_INET; 
    neighbour.sin_port = htons(left_peer_port); 
    memcpy(&neighbour.sin_addr, neighbour_info->h_addr_list[0], neighbour_info->h_length); 

    printf("\nconnected to port %d\n", left_peer_port); 
    //To talk to the neighbour 
    printf("\ncomes here\n"); 


//Listen on this socket connection for potato 

    int send_peer_len; 
    int nfds; 

    nfds = MAX(MAX(neighbour_socket, s2), s1); 

// clear the set ahead of time 
    FD_ZERO(&writefds); 

// add our descriptors to the set 
    FD_SET(neighbour_socket, &writefds); 
    FD_SET(s1, &writefds); 
    FD_SET(s2, &writefds); 

//FD_SET(s2, &writefds); 


    FD_ZERO(&readfds); 
    FD_SET(neighbour_socket, &readfds); 
    FD_SET(s1, &readfds); 
    FD_SET(s2, &readfds); 

//select() 

// since we got s2 second, it's the "greater", so we use that for 
// the n param in select() 
//n = s1 + 1; 

// wait until either socket has data ready to be recv()d (timeout 10.5 secs) 
    tv.tv_sec = 10; 
    tv.tv_usec = 500000; 

    int fds[3]; 
    fds[0] = s1; 
    fds[1] = s2; 
    fds[2] = neighbour_socket; 
    int p = 0; 
    int p_flag = 0; 

    while (1) { 
     printf("\n nfds = %d , p = %d \n", nfds, p); 
     char buf_msg[64]; 


     //This is where the error occurs // 

     rv = select(nfds, &readfds, NULL, NULL, 0); 

     //This is where the error occurs // 

     if (rv == -1) { 
      perror("select"); // error occurred in select() 
     } else if (rv == 0) { 
      printf("Timeout occurred! No data after 10.5 seconds.\n"); 
     } else { 
      // one or both of the descriptors have data 
      //reading message from server 
      int select_fd; 
      for (select_fd = 0; select_fd <= nfds; select_fd++) { 

       if (FD_ISSET(select_fd, &readfds) != 0) { 
        if (select_fd == s1) { 

         recv_len = 0; 
         recv_len = recv(s1, buf_msg, 34, 0); 
         if (recv_len < 0) { 
          perror("recv"); 
          exit(1); 
         } 
         buf_msg[recv_len] = '\0'; 
         printf("\nreceived from server = %s\n", buf_msg); 
         //send to neighbour 

         int sc3; 
         sc3 = connect(neighbour_socket, (struct sockaddr *) &neighbour, sizeof(neighbour)); 
         if (sc3 < 0) { 
          perror("connect:"); 
          exit(sc3); 

         } 

         str = malloc(1); 
         strcpy(str, buf_msg); 
         send_len = send(neighbour_socket, str, strlen(str), 0); 
         printf("\n send - len - s1 - %d\n", send_len); 
         if (send_len != strlen(str)) { 
          perror("send"); 
          exit(1); 
         } 
         start_flag = 1; 
         //FD_CLR(s1, &readfds); 

         printf("\ncrossed server\n"); 

        } else if (select_fd == s2) { 

         int list_len = sizeof incoming; 
         printf("\ninside client\n"); 
         printf("\nWaiting for accept in S2\n"); 
         if (p_flag == 0) { 
          p_flag = 1; 
          p = accept(s2, (struct sockaddr *) &incoming, &list_len); 
          printf("\nConnection accepted in S2\n"); 
          if (p < 0) { 
           perror("bind:"); 
           exit(rc); 
          } 
         } 
         nfds = MAX(nfds, p); 
         recv_len = 0; 
         buf_msg[recv_len] = '\0'; 
         recv_len = recv(p, buf_msg, 34, 0); 
         if (recv_len < 0) { 
          perror("recv"); 
          exit(1); 
         } 
         buf_msg[recv_len] = '\0'; 
         printf("\nreceived from client = %s\n", buf_msg); 
         //send to neighbour 

         //if(start_id!=1){ 
         int sc3; 
         sc3 = connect(neighbour_socket, (struct sockaddr *) &neighbour, sizeof(neighbour)); 
         if (sc3 < 0) { 
          perror("connect:"); 
          //exit(sc3); 
         } 
         //} 

         str = malloc(1); 
         strcpy(str, buf_msg); 
         send_len = send(neighbour_socket, str, strlen(str), 0); 
         printf("\n send - len - s2 - %d\n", send_len); 
         if (send_len != strlen(str)) { 
          perror("send"); 
          exit(1); 
         } 

        } else if (select_fd == neighbour_socket) { 

         printf("\ncomes in\n"); 

        } else if (select_fd == p && p != 0) { 

         int list_len = sizeof incoming; 
         printf("\ninside p\n"); 
         recv_len = 0; 
         buf_msg[recv_len] = '\0'; 
         printf("\nwaiting at recv in P\n"); 

         recv_len = recv(p, buf_msg, 34, 0); 

         printf("\ncrossed at recv in P\n"); 
         if (recv_len < 0) { 
          perror("recv"); 
          exit(1); 
         } 
         buf_msg[recv_len] = '\0'; 
         printf("\nreceived from client = %s\n", buf_msg); 
         //send to neighbour 
         str = malloc(1); 
         strcpy(str, buf_msg); 
         send_len = send(neighbour_socket, str, strlen(str), 0); 
         printf("\n send - len - neighbour - %d\n", send_len); 
         if (send_len != strlen(str)) { 
          perror("send"); 
          exit(1); 
         } 
        } 
       } 
      } 

      FD_ZERO(&readfds); 
      //FD_SET(neighbour_socket,&readfds); 
      FD_SET(s1, &readfds); 
      FD_SET(neighbour_socket, &readfds); 

      if (p_flag == 1) { 
       printf("\nsetting P\n"); 
       FD_SET(p, &readfds); 
       FD_SET(s2, &readfds); 

       p_flag = 0; 
      } else { 
       printf("\nNot setting P\n"); 
       FD_SET(s2, &readfds); 
      } 
     } 
    } 
    close(s1); 
    close(s2); 
} 

Заранее спасибо.

ответ

3

Первым параметром select должен быть максимальный дескриптор файла плюс один. Насколько я могу судить в этом огромном куске кода, который вы опубликовали, вы забыли это «плюс один».

+0

Это, и fd_set необходимо повторно инициализировать каждый раз. В этом коде это не так, это делается за пределами цикла, что неверно. – nos

+0

Это правда, но код, который может быть опубликован, может быть таким, что рядом с ним есть FD_ZEROs/FD_SET. - учитывая, что в отступе я понятия не имею, находятся ли они в в нужном месте или нет, или если они достаточны. – Mat

+0

Итак, как только FD_ISSET станет истинным и выполнит одно из условий в цикле for, которое следует за ним, FD_SET должен быть выполнен снова. Опять мне нужно установить все FD (s1, s2, p) в readfs? и ждите еще раз()()? У меня есть еще одно связанное сомнение, я заметил, что select() может обнаружить вызов connect(), и он переходит от оператора select() к следующему оператору. Но он не распознает вызов send(), он все еще ждет в select(), даже если в одном из своих сокетов в readfds выполняется функция send(). Можете ли вы объяснить это поведение? –

3

Я считаю Mat has found the underlying problem. Но я думаю, что есть гораздо более серьезная проблема здесь:

int send_len; 
char *str=malloc(1); 
sprintf(str,"%d",peer_port); 
printf("\nport-here=%s\n",str); 

Вы испортили вашу кучу с sprintf(3) вызова. Возможно, это не важные данные, которые вы перезаписали, и, может быть, malloc(3) никогда не будет на самом деле выделять один байт, но это плохое предположение. Вы должны выделить не менее шесть байт для номера порта: пять для цифр в 65535 и один для конечного ASCII NUL\0 байт.

buf[recv_len] = '\0'; 
    char *temp_port; 
    //printf("\n-%s\n",buf); 
    if (!strcmp("close", buf)) 
     printf("%s",buf); 
    //break; 
    else{ 
    char *temp_buffer=malloc(1); 
    char *id=malloc(100); 
    char *pp=malloc(1); 
    strcpy(temp_buffer,buf); 

В предыдущем выборе, вы сохранили \0 в конце buf, так что вы, вероятно работать со строкой какой-то. Но в нескольких строках вы выделяете один байт, а затем переходите к копированию содержимого buf в этот единственный байт. ASCII NUL полностью использует этот байт, не оставляя места для полученной строки. Но strcpy(3) не работает таким образом - он скопирует содержимое buf, до этого '\0' персонажа, в память, начиная с вашего байта. Ты снова уничтожил свою кучу. Но на этот раз он может переписать значительно больше пяти байтов - и все они находятся под контролем удаленного однорангового узла.

Heap overflows are extremely dangerous.Я нашел более 350 ссылок на полезные ошибки в программах, которые происходят непосредственно из переполнения кучи в старом архиве, который у меня есть из проекта Common Vulnerabilities and Exposures.

Не развертывайте эту программу на общедоступных машинах, пока не устраните эти проблемы. Это представляет собой значительный недостаток безопасности. Найдите все экземпляры malloc(1) и замените его на правильно объем памяти, который должен быть выделен. Как только вы это сделаете, запустите свою программу с помощью MALLOC_CHECK_=1 или под управлением valgrind(1), чтобы помочь вам найти дополнительные проблемы с распределением памяти.

+0

Спасибо. Это было действительно полезно. Я лучше задался вопросом, как избежать уязвимостей в куче. –

1

Считаете ли вы использование poll() вместо select()? Легче отлаживать и масштабировать элегантно, насколько вам нужно.

+0

Ну, я хотел поработать с select(), чтобы понять это. Однако я также попытаюсь использовать poll(), как только это будет исправлено. Спасибо. –

Смежные вопросы