【问题标题】:Using thread to write and select to read使用线程写入和选择读取
【发布时间】:2014-02-23 03:49:38
【问题描述】:

有没有人尝试过在非阻塞模式下创建socket,并使用专用线程写入socket,但是使用select系统调用来识别是否有数据可用于读取数据。

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

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

【问题讨论】:

  • 查看write的返回码就知道是否成功,写入了多少字节。

标签: linux multithreading sockets


【解决方案1】:

有没有人尝试过在非阻塞模式下创建socket,并使用专用线程写入socket,但是使用select系统调用来识别是否有数据可用于读取数据。

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

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

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

select() 可以与阻塞和非阻塞套接字一起使用。与阻塞套接字相比,它更常用于非阻塞套接字。

有没有办法知道写入的状态 无需阻止即可调用。

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

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

【讨论】:

    【解决方案2】:

    有没有办法知道写调用的状态而无需 阻止它。

    如果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)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-09
      • 1970-01-01
      • 2021-08-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多