0

select() 呼び出しを使用して複数のソケットをリッスンするクライアントサーバープログラムに取り組んでいます。しかし、それらのソケットの 1 つにメッセージがありますが、select() 呼び出しはそれを認識せず、無期限に待機しています。

プログラムには、マスターとクライアントの 2 つのエンティティがあります。マスターは、処理するクライアントの数を認識しており、クライアントが接続するのを待ちます。クライアントの確認を受信すると、その情報を保存します。すべてのクライアントが接続されると、隣接するクライアントの情報をすべてのクライアントに送信して、ネットワークを形成できるようにします。それはここにあります、私は多くのソケットを監視するためにselect()を使用します、マスターはそれに接続されているすべての子へのソケットを持っていますクライアントは3つのメインソケットを持っていますその隣人が接続を待機するソケット (つまり、隣人の S2) p- その隣人からの接続の結果であるソケット (s2 の受け入れ - ths を返します)接続して一度。

最初に、サーバーは文字列「hello」をクライアントの1つに送信し、クライアントはこのメッセージを受信して​​隣人に渡します。このようにして、文字列がサーバーからこのメッセージを受信した最初の子に戻ると、それを渡しますその隣に。しかし、すべての子は 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);
} 

前もって感謝します。

4

3 に答える 3

3

の最初のパラメータselectは、最大のファイル記述子に 1 を加えたものでなければなりません。あなたが投稿したその巨大なコードの塊で私が知る限り、あなたはその「プラスワン」を忘れていました。

于 2011-10-22T07:21:39.233 に答える
3

私は、Mat が根本的な問題を発見したと信じています。しかし、ここにはもっと大きな問題があると思います:

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

sprintf(3)呼び出しでヒープが破損しました。上書きしたのは重要なデータではないかもしれませんし、実際に1 バイトmalloc(3)を割り当てることはないかもしれませんが、それは悪い仮定です。ポート番号には少なくとも6バイトを割り当てる必要があります。5 つは数字の数字用、1 つは末尾の ASCIIバイト用です。65535NUL \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);

前の選択では、 a\0を の末尾に保存したbufため、おそらく何らかの文字列を操作していると思われます。しかし、数行で、1 バイトを割り当ててから、bufその 1 バイトに の内容をコピーします。ASCIINULはそのバイトを完全に使用し、受け取った文字列のためのスペースを残しません。しかしstrcpy(3)、そのようには機能しません-bufその文字までの内容を、'\0'1バイトから始まるメモリにコピーします。あなたは再びヒープを破壊しました。しかし今回は、5 バイトを大幅に超える上書きが可能であり、すべてリモート ピアの制御下にあります。

ヒープ オーバーフローは非常に危険です。Common Vulnerabilities and Exposuresプロジェクトから私が持っている古いアーカイブで、ヒープ オーバーフローから直接派生するプログラムの悪用可能なバグへの 350 以上の参照を見つけました。

これらの問題を修正するまで、このプログラムを公的にアクセス可能なマシンに展開しないでください。これは重大なセキュリティ上の欠陥を表しています。のすべてのインスタンスを見つけて、割り当てる必要がある正しい量のメモリにmalloc(1)置き換えます。これが完了したら、メモリ割り当ての問題をさらに見つけるのに役立つように、の制御下でプログラムを実行してください。MALLOC_CHECK_=1valgrind(1)

于 2011-10-22T07:50:44.693 に答える
1

select() の代わりに poll() を使用することを検討しましたか? デバッグが簡単で、必要な数に合わせてエレガントにスケーリングできます。

于 2011-10-22T08:24:17.810 に答える