Linux套接字和多线程程序

dced5bon  于 9个月前  发布在  Linux
关注(0)|答案(2)|浏览(82)

我必须写一个简单的客户端-服务器应用程序,使用Unix数据报套接字。客户端可以根据服务器的请求向服务器发送信息,也可以根据自己的请求从服务器接收信息。
我有一个想法,一个线程将等待用户输入,决定我们想要发送什么请求到服务器,另一个线程将只等待来自服务器的套接字上的消息,如果它是我们请求的消息,它将把它写入标准输出,如果它是服务器请求线程将写入服务器请求的内容。我会使用互斥,这样两个线程就不会同时写入同一个套接字。
我的问题是,如果一个线程从某个套接字读取数据,同时另一个线程使用同一个套接字发送数据,套接字将如何行为,它安全吗?或者我也应该在这种情况下使用互斥量?

chhqkbe1

chhqkbe11#

内核结构通常以线程安全的方式构建;套接字也不例外。如果你需要担心什么的话,那不是使用套接字和线程的安全性,而是程序的逻辑。
另外,我想提一下,流套接字是全双工的,这意味着读/写可以同时安全地发生,这是怎么发生的呢?内核为您锁定或确保您可以同时进行发送和接收。
对于全双工参数:
http://www.kernel.org/doc/man-pages/online/pages/man2/socket.2.html对于内核结构是线程安全的:
我找不到链接来支持这一点,但我有99%的把握。
P.S.当有疑问时,测试可能会有所帮助
编辑:
请,如果我说的是错的,在投票之前发表评论。

编辑2:

在这里,您可以发现POSIX标准规定,除了在2.9.1节中定义的列表之外,其所有函数都必须是线程安全的
http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html

rm5edbpk

rm5edbpk2#

在Linux和windows中,send()和recv()调用(通常用于TCP,但我认为也可以用于UDP)可能会提前返回,而没有发送您想要发送的全部数据。这将导致线程问题,因为您的消息将被分割。
我发现用以下属性 Package recv()和send()函数是最简单的:

  • 只有在我们请求的所有数据都写入套接字后才返回
  • 线程安全

然后在所有我会使用send/recv的地方使用 Package 器。
下面是 Package 器的代码(请随意更改错误处理):

//linux (must change SOCKET types to int)
//#include <sys/socket.h>

//windows 
//#include <Winsock2.h>
//#include <ws2tcpip.h>

//blocks until the full amount of bytes requested are read
//thread safe
//throws exception on error
void recv_bytes(SOCKET socket, char* buf, int len, int flags){

    static std::mutex mtx;

    mtx.lock();

    int bytes_received = 0;

    while (bytes_received != len){

        int bytes = recv(socket, buf + bytes_received, len - bytes_received, flags);

        //error check
        if (bytes == 0){
            mtx.unlock();
            throw std::exception("Network Exception");
        }

        bytes_received += bytes;

    }

    mtx.unlock();

}


//blocks until the full amount of bytes requested are sent
//thread safe
//throws exception on error
void send_bytes(SOCKET socket, char* buf, int len, int flags){

    static std::mutex mtx;

    mtx.lock();

    int bytes_sent = 0; 

    while (bytes_sent != len){

        int bytes_s0 = send(socket, buf, len, flags);

        if (bytes_sent == SOCKET_ERROR) {
            mtx.unlock();
            throw std::exception("Network Exception");
        }

        bytes_sent += bytes_s0;

    }

    mtx.unlock();
}

相关问题