为什么read()在原始套接字上关闭/关闭后没有返回?

时间:2016-05-30 10:42:10

标签: c sockets bluetooth network-programming hci

我有一个线程,它在一个循环中读取来自原始HCI套接字的消息,如下所示:

void* loop_hci (void* args) {
    params_hci_t* params = (params_hci_t*) args;
    int result_hci = 0;
    uint8_t* buf_hci = calloc(1, HCI_EVENT_MAX_LENGTH);
    while (!poll_end()) {
        result_hci = read(params->hci_sock, buf_hci, HCI_EVENT_MAX_LENGTH);
        if (result_hci > 0) {
            // ... do stuff with the received data
        }
    }
    ancs_pdebug("HCI loop shutting down...");
    return NULL;    
}

poll_end()函数可以正常工作。它返回0直到收到SIGINT信号,之后返回1.

在主线程中,我创建了这样的套接字:

hci_sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);

还有线程:

ph->hci_sock = hci_sock;
pthread_create(&t_hci, NULL, &loop_hci, ph);

然后经过一段时间的调用关闭(在主线程中):

shutdown(hci_sock, SHUT_RD);

我假设read()应该在我调用shutdown()之后返回,我在不同的线程中使用相同的方法来处理L2CAP套接字并且它工作正常。但它并没有。主线程中的pthread_join(t_hci, NULL)调用永远不会返回。

套接字工作正常。我可以从中读取消息。我也尝试调用close(我在线程结束后执行),但结果是相同的。

可能是什么问题,或者我的假设是错误的?

1 个答案:

答案 0 :(得分:2)

您遇到的问题可能是因为您处理套接字和多线程的方式。您不应该使用原始套接字关闭。它适用于连接套接字我从未尝试使用原始套接字或数据包套接字。但是有一个建议是杀死或取消我会避免的线程,因为杀死一个线程是暴力的,你有可能不按有序的方式处理资源。相反,您应该以不同的方式设计解决方案:

  1. 一种可能性是使用非阻塞套接字以及select,poll或epoll。在套接字准备就绪或超时之前,您将有一个等待select / poll / epoll的循环。当你想要关闭套接字时,你只需设置一个变量,例如endLoop为true,表示轮询线程应该离开循环。请参阅man for select:http://man7.org/linux/man-pages/man2/select.2.html

  2. 例如,在Thrift服务器中使用的其他可能性是使应用程序使用某些代码向自己发送特殊消息。侦听线程解除阻塞并读取此特殊消息,指示它应检查是否必须完成侦听(例如,通过读取变量值)。

  3. 因此,当他正在侦听线程正在侦听或读取时,主线程会将变量endLoop变量设置为true,表示它已完成,或者它将执行(2)取消阻止侦听线程。

    这两个选项是处理问题的优雅方式。使用非阻塞套接字(1)或通过向自身发送消息来解除阻塞的读取或侦听线程。