繁体   English   中英

应用程序可以处理N个接受连接,每个接受使用一个独立的线程

[英]Can an application handle N accept connections and each accept uses an independent thread

我有C linux TCP客户端/服务器应用程序。 我想到了一个奇怪的情况,但是我不知道此应用程序是否会产生任何后果。 我的服务器端可以接受N个连接,例如,该服务器将接受100个连接。 在这种情况下,我在主线程中创建了侦听套接字,然后创建了100个线程,并且每个线程都有一个独立的accept()和select()iomux,每个线程只能接受一个连接。

我在这里担心的是,如果两个同时的accept()由于选择可以接受同一个套接字(连接),并且可以在同一套接字上读取,则我不知道同时接受在内核中是否是线程安全的,并且只有一个accept可以处理该传入连接,另一个会等待另一个连接?

我在可以正常工作的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;
}

根据POSIX, accept()是线程安全的,并且是可重入的。

这意味着在同一描述符上两次调用accept不应给出未定义的行为。 其中一个accept将打开套接字,另一个将返回错误。

您可以在那看到更多:

是accept()线程安全的吗? BSD / Posix插槽可重入吗?

只有一个线程将accept连接。 内核确保了这一点。 在Unix / POSIX世界中已经有很长时间了。

到目前为止,只有一个线程会accept() ...-但在此之前, 所有线程将被触发具有select()返回,这可能不是您想要的。

因此,如果您有N个线程在select()休眠,并且一个连接进入所有线程,则将唤醒,但仅需要一个线程,因为只有一个线程可以成功accept()

在多个线程/进程的同一套接字对象上使用accept()不仅是标准的,而且是广泛使用的策略。 据我所知, apache做到了。 Nginx也这样做,但是方式略有不同。

请注意: select()可以唤醒多个线程,但是其中只有一个线程将接受连接,而其他线程将要么a)挂在accept()要么b)返回-1并在非阻塞IO的情况下将errnoEAGAIN 由于使用的select()之前接受()我想socket描述符非阻塞模式。 因此,这可能导致某些线程永远不会为连接服务。

我也建议您不要在多个线程中关闭同一套接字。 这可能会导致非常令人讨厌且难以调试的后果。 使用wrapper和shared_ptr或为线程之一分配“套接字所有者”的角色。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM