使用线程写入并选择读取

时间:2014-02-23 03:49:38

标签: linux multithreading sockets

是否有人试图以非阻塞模式创建套接字并使用专用线程写入套接字,但使用select系统调用来识别数据是否可用于读取数据。

如果套接字是非阻塞的,则写入调用将立即返回,并且应用程序将不知道写入的状态(如果它已通过或失败)。

有没有办法知道写调用的状态而不必阻塞它。

2 个答案:

答案 0 :(得分:2)

  

是否有人试图以非阻塞模式创建套接字并使用专用线程写入套接字,但使用select系统调用来识别数据是否可用于读取数据。

是的,它运作正常。插座是双向的。它们有独立的读写缓冲区。让一个线程将数据写入套接字而另一个线程同时从同一个套接字读取数据是完全可以接受的。两个线程可以同时使用select()

  

如果套接字是非阻塞的,则写入调用将会   立即返回,申请不会   知道写入的状态(如果通过或失败)。

阻塞套接字也是如此。出站数据在内核中缓冲并在后台传输。这两种类型之间的区别在于,如果写缓冲区已满(例如,如果对等方没有读取并且足够快地读取数据),则非阻塞套接字将无法接受更多数据并报告错误代码({{1在Windows上,WSAEWOULDBLOCKEAGAIN在其他平台上),而阻塞套接字将等待缓冲区空间清除,然后将待处理数据写入缓冲区。阅读也一样。如果入站内核缓冲区为空,则非阻塞套接字将失败并显示相同的错误代码,而阻塞套接字将等待缓冲区接收数据。

EWOULDBLOCK可以与阻塞和非阻塞套接字一起使用。它比非阻塞套接字更常用于非阻塞套接字。

  

有没有办法知道写的状态   打电话而不必阻止它。

在非Windows平台上,您可以使用select()或等效内容来检测套接字在写入之前何时可以接受新数据。在Windows上,如果未立即完成挂起的读/写操作,有一些方法可以接收通知。

但无论哪种方式,出站数据都会写入内核缓冲区而不会立即传输。写入函数,无论是在阻塞还是非阻塞套接字上调用,只报告将数据写入该缓冲区的状态,而不是向对等方传输数据的状态。了解传输状态的唯一方法是让对端在收到数据后明确发回应答消息。有些协议可以做到这一点,有些则没有。

答案 1 :(得分:1)

  

有没有办法知道写呼叫的状态而没有   阻止它。

如果write来电的结果为-1,请检查errno以查看EAGAINEWOULDBLOCK。如果这是其中一个错误,那么它是良性的,你可以回去等待一个选择的电话。示例代码如下。

int result = write(sock, buffer, size);

if ((result == -1) && ((errno == EAGAIN) || (errno==EWOULDBLOCK)) )
{
    // write failed because socket isn't ready to handle more data.  Try again later (or wait for select)
}
else if (result == -1)
{
    // fatal socket error
}
else
{
    // result == number of bytes sent.
    // TCP - May be less than the number of bytes passed in to write/send call.
    // UDP - number of bytes sent (should be the entire thing)
}