【问题标题】:Windows socket seems to be Non DuplexWindows 套接字似乎是非双工的
【发布时间】:2013-05-01 21:12:00
【问题描述】:

我在写一个客户端-服务器程序,客户端是C++/winapi,服务器是C#/.net。

客户端有一个循环,它从服务器读取(并且可能会阻塞调用线程 [表示 t1],这对我来说很好)。它还有另一个线程 [表示 t2] ,等待一个超时的事件对象。

如果达到超时(并且事件尚未被单选),t2 线程将在同一个套接字上写入(精确地按字节)。

我遇到的问题是,在 t1 上的读取返回之前,写入似乎不会返回(在某些合法的场景中,它永远不会发生),好像套接字不是全双工的。

P.S : socket 是一个 AF_INET/ SOCK_STREAM,我使用 Readfile 和 WriteFile 作为 socket IO。

谢谢。

【问题讨论】:

    标签: c multithreading sockets winapi thread-safety


    【解决方案1】:

    不是 read() 和 write() 或 send() 和 recv() 的套接字都不是这样。你必须有一些你自己的同步。

    【讨论】:

      【解决方案2】:

      我使用 WinSock 编程已有十多年了,我可以向您保证,套接字始终是全双工的。

      WriteFile()(或send()WSASend())在任何时间内阻塞调用线程的唯一方法是,如果套接字以阻塞模式运行并且其等待传输的数据的出站队列已经完全满(队列的大小由SO_SNDBUF 套接字选项控制)。这表明另一方(您的 C# 服务器)没有从其套接字端点读取入站数据并及时确认接收到的数据,因此您的套接字端点可以从其出站队列中删除该数据,以便可以接受新数据进行传输。

      如果您不想阻止对WriteFile() 的呼叫,您可以:

      1. 启用SO_SNDTIMEO 套接字选项以指定阻塞写入的超时时间。

      2. 在向套接字写入任何新内容之前,使用select()WSAAsyncSelect()WSAAsyncEvent() 检测套接字何时真正可写(即何时可以接受数据而不阻塞)。

      3. 切换到非阻塞 I/O、异步重叠 I/O 或 I/O 完成端口。

      【讨论】:

      • 这个怎么样? stackoverflow.com/a/16708230/886887 套接字是一个特殊的例外吗?如果您使用的是 ReadFile/WriteFile 而不是套接字函数,该例外是否适用?
      • socket() 创建一个在内部使用重叠 I/O 的套接字。为避免使用重叠 I/O,您必须改为调用 WSASocket() 并省略 WSA_FLAG_OVERLAPPED 标志。但在大多数情况下,这通常是不可取的。
      • 这是否意味着如果您使用 ReadFile 和 WriteFile 您需要使用重叠 I/O,即指定有效的 OVERLAPPED 结构?这可能是 OP 的问题吗?
      • 真正的问题是 OP 完全使用带有套接字的 ReadFile()WriteFile()。他应该改用recv()/WSARecv()send()/WSASend()
      猜你喜欢
      • 2016-06-18
      • 1970-01-01
      • 2015-03-14
      • 2018-06-17
      • 2011-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-26
      相关资源
      最近更新 更多