2

C linux TCP クライアント/サーバー アプリケーションがあります。奇妙なシナリオを思いつきましたが、このアプリケーションに何らかの影響があるかどうかはわかりません。N 接続を受け入れることができるサーバー側があります。たとえば、このサーバーは 100 接続を受け入れます。このシナリオでは、メイン スレッドでリッスン ソケットを作成し、次に 100 のスレッドを作成します。各スレッドには独立した accept() および select() iomux があり、各スレッドは 1 つの接続しか受け入れることができません。

ここでの私の懸念は、選択が同じソケットで読み取る準備ができているために2つの同時accept()が同じソケット(接続)を受け入れたい場合、同時受け入れがカーネルでスレッドセーフであり、1つだけであるかどうかわかりません受け入れてその着信接続を処理でき、もう一方は別の接続を待機しますか?

正常に動作する RedHat マシンでそれを試してみましたが、デッドロックを回避できるほど幸運かどうかはわかりません!

ありがとう

rc = bind(sd, (struct sockaddr_in *)& groupSock, sizeof(struct sockaddr_in));
    CHECK_VALUE("Bind address error", rc, 0, goto cleanup);

    rc = listen(sd, 10);
    CHECK_VALUE("listen", rc, 0, goto cleanup);

    for(; count< num_socks; count++){

            par_data[count].sd = sd;
            par_data[count].thread_num = count;
            par_data[count].err_chk = -1;

            rc = pthread_create(&thread_id[count], NULL, accept_sock_thread,  (void *)& par_data[count]);
            CHECK_VALUE("pthread_create", rc, 0, goto cleanup);


    }

void * accept_sock_thread(void* atr){

    int                     rc;
    int                     sock            = INVALID_SOCKET;
    int                     datalen         = config.traffic;
    char                    *databuf        = NULL;
    struct thread_data      *data           = NULL;
    struct sockaddr_in      tcp_remote;
    struct timeval          t;
    socklen_t               size;
    fd_set                  socks;

    databuf = malloc(sizeof(char) * datalen);
    memset(databuf, 0, datalen);

    data = (struct thread_data*) atr;
    DEBUG(my_debug_flags, ENTER_FUNCT, ("Enter Function accept_sock_thread thread_num %d \n", data->thread_num));


    FD_ZERO(&socks);
    FD_SET(data->sd, &socks);
    t.tv_sec = 25;
    t.tv_usec = 0;
    rc = select(data->sd + 1 , &socks, NULL, NULL,&t);
    if(rc < 0){
            VL_MISC_ERR(("Error in select with Errno: %d", errno));
            goto cleanup;
    }
    else if(rc == 0){
            VL_MISC_ERR(("Accept Select returned a TIEMOUT."));
            goto cleanup;
    }


    size = sizeof(struct sockaddr_in);
    sock = accept(data->sd, (struct sockaddr *)& tcp_remote, &size);
    CHECK_NOT_EQUAL("tcp accept error", sock, INVALID_SOCKET,  goto cleanup);
cleanup:
    //      sleep(2); /* avoid EOF */
    if(sock != INVALID_SOCKET){

            rc = close(sock);
            if(rc != 0){
                    data->err_chk = -1;
            }
    }
           return NULL;
}
4

4 に答える 4

2

accept()POSIX に従って、スレッドセーフで再入可能です。

これは、同じディスクリプタで 2 つの accept を呼び出しても、未定義の動作が発生しないことを意味します。Accept の 1 つはソケットを開き、もう 1 つはエラーを返します。

そこにもう少し見ることができます:

accept() はスレッドセーフですか? BSD/Posix ソケットは再入可能ですか?

于 2013-11-12T13:21:56.440 に答える
1

accept接続に向かうスレッドは 1 つだけです。カーネルはこれを保証します。unix/posix の世界では、非常に長い間このようになっています。

于 2013-11-12T13:22:25.380 に答える