【问题标题】:Use non-blocking TClientSocket inside a thread在线程内使用非阻塞 TClientSocket
【发布时间】:2015-12-17 14:42:27
【问题描述】:

这篇Embarcadero 文章描述了在线程内使用阻塞套接字。如果我将我的套接字创建为ctNonBlocking,并且只向套接字写入简单的消息,我应该使用TClientWinSocket.SendText

// Inside TThread::Execute: Option 1
strMessage := 'Hello!';
mySocket.Socket.SendText(strMessage);

或者我应该创建一个TWinSocketStream 并使用Write

// Inside TThread::Execute: Option 2
strMessage := 'Hello!';
stream := TWinSocketStream.Create(mySocket.Socket, 1000);
stream.Write(strMessage[1], Length(strMessage));

我发现我的应用程序在退出时抛出异常(在 DPR 文件中的 Application.Run() 之后并且无法调试),如果我注释掉所有 TClientSocket 代码,该异常就会消失。

【问题讨论】:

  • 你为什么要做这种奇怪的事情?如果要引发线程,为什么要非阻塞? TClientSocket 实例的构造函数调用在哪里?请不要说您将其转储到表单上:((
  • 在创建线程后立即在线程的初始化函数中创建套接字,如@9​​87654329@ 然后mySocket.ClientType := ctNonBlocking;。我将套接字设置为非阻塞,因为它看起来更容易,但我是来学习的。如果这是一件奇怪的事情,那么我将看看阻止选项......
  • 查看对已接受解决方案的评论。基本上我遵循了问题中提到的 Embarcadero 文章中的示例代码(将 TClientSocket 从非阻塞模式转换为阻塞模式)。事实证明这是相对简单的。当然,我之前使用它的方式很“奇怪”……在线程内以阻塞模式使用它效果很好!

标签: multithreading sockets delphi delphi-7


【解决方案1】:

如果套接字处于非阻塞模式,则不能使用TWinSocketStream。如果套接字未处于阻塞模式,TWinSocketStream 的构造函数将引发异常。这在documentation 中有说明:

使用 TWinSocketStream 通过阻塞套接字连接读取或写入信息...

...

注意:TWinSocketStream 不适用于非阻塞套接字。

TClientSocket 在非阻塞模式下可以在工作线程中正常工作(尽管首选阻塞模式),前提是该线程具有消息循环。原因是因为在非阻塞模式下,TClientSocket 创建了一个内部窗口并将其与套接字关联。此窗口接收来自 WinSock 的消息以触发 TClientSocket 的事件。因此,非阻塞模式下的TClientSocket 必须在同一个线程上下文中创建、使用和销毁。不要跨线程边界访问它。

TClientSocket 在阻塞模式下没有这个限制。

【讨论】:

  • 我会避免 TClientSocket 在线程中处于非阻塞模式。它使用 AllocateHWnd 创建它的窗口,并且该函数不是线程安全的。它确实在大多数情况下都有效,但随后会在这里和那里失败。
  • TClientSocket 只能从同一个线程中访问。 “外部世界”与线程交互的唯一方法是将消息添加到 TStringList 中(用关键部分包装以进行同步)或从线程获取统计信息,例如已发送多少条消息。线程检查 TThread::Execute 中的新消息。感谢 cmets Remy,将考虑切换到阻塞套接字调用。
  • @Remy:与TWinSocketStream 相关的快速问题。文档(和 Embarcadero 示例)显示 TWinSocketStream 每次都被创建、使用和释放。一次创建TWinSocketStream 并反复使用它是否有问题?在最初的问题中,如果将套接字更改为阻塞,TWinSocketStream 是否优先于Socket.SendText(...);
  • 您可以创建TWinSocketStream 的单个实例,并在套接字连接的整个生命周期内重复使用它。使用TWinSocketStream 的唯一真正原因是它的超时处理,但还有其他方法可以在没有它的情况下使用超时。 SendText() 的问题在于它可以发送部分数据,即使是在阻塞套接字上,它也会返回发送的字节数,而不是字符数。这并不理想。我从不使用SendText()ReceiveText(),总是使用SendBuf()ReceiveBuf(),或者TWinSocketStream
  • 今天早上我把我的代码从非阻塞转换为阻塞,事实证明它没有我担心的那么令人生畏!重新连接到服务器时出现问题(在我停止服务器侦听指定端口后,然后再次开始侦听)。通过在队列中发送任何消息后设置mySocket.Active := False;,它每次都重新连接。感谢您抽出宝贵时间,雷米!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-06
  • 1970-01-01
  • 1970-01-01
  • 2011-05-12
  • 2019-02-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多