我正在编写一个我在C ++ Builder项目中使用的网络DLL。此DLL适用于远程FTP服务器。调用recv()
时,我注意到一种奇怪的行为。有时它返回0.但是在另一个线程中,在同一个套接字上调用recv()
时,会按预期接收数据。
这是什么意思?我还注意到在DLL线程中调用Application->ProcessMessage()
会加速数据接收。
但是有什么不对? ProcessMessages()
只是处理窗口消息还是我遗漏了什么?
谢谢
答案 0 :(得分:3)
如果我理解正确并且您正在尝试recv
并行线程中的SOCKET
,那么不要这样做,没有什么可以从中获益。您recv
的数据已被底层系统缓冲,并且您正在访问它,您可以做的是为recv
创建多个缓冲区,以便在它返回数据时您可以传递一个缓冲区到“上层”进行处理,并使用另一个进行新的recv
调用。您还可以使用一个大缓冲区,其中包含用于处理的通知以及用于接收的部分。系统可能具有禁止在同一套接字上进行多次读取的锁定,因此一个recv
的结果为0
。如果它没有那么你可能会得到一些几乎随机分割的数据。
编辑:完整和长期解释
我认为使用多个线程从单个套接字读取是没有用的
套接字是一种软件监管的东西。您的网络设备不会创建任何“连接”,它只处理收到的数据并将它们包装/解包到IP
(或任何其他
支持的Internet Layer)数据包(以前取决于网络设备,其中一些几乎完全是由OS模拟的软件,实际上只执行基本的“写入tx-read rx”服务,但对我们来说是相同的交易)。 WinSock2
服务识别具有特定数据的数据包(您已经注意到),以便您可以同时使用一个网络设备
与多个同伴沟通。 WinSock2
会在将流量发送给您之前对其进行监控。换句话说:当您即将获得成功recv
数据时
已经存在并且底层系统检查了您在recv
中用作参数的套接字,并且仅将已经标记为数据的数据移交给您
对于那个插座。从一个套接字读取多个线程(没有几乎无用的MSG_PEEK
)会使系统(如果没有锁)复制未知的字节数
到线程1中recv
中提供的位置,并按照复制字节数永久地将内部指针递增到数据,然后,在整个数据可用之前
recv
被复制到location1,另一个线程将启动并复制未知数量的字节,从而也将内部指针递增到那么多字节的数据。
理想情况下,这种类型读取的结果是从线程1中提供的位置存储的数据的一半,另一半从线程2中提供的位置开始。由于理想的结果是不确定的(系统为两个线程分配的时间不是保证是平等的,你最终会得到未分类的数据而没有任何排序方法
它,因为底层系统用来知道哪些数据属于哪个套接字将无法使用的信息。
由于你的系统最有可能比你的网络设备更快,我支持我的两个解决方案,首先是因为我一直使用这种方法进行大小数据传输:
为每个连接的套接字和一个循环缓冲区创建一个读取线程,缓冲区的大小取决于您希望接收的块的大小以及进一步处理这些内容所需的时间,保存当前读取位置,保存“处理计数”,当接收到数据时通知线程/线程它应该处理缓冲区中的数据,保存用于读取的数据的位置,如果没有缓冲区空间则继续recv
正在处理其他等待直到有(必须实现这一点,以防你的计算机在某处窒息,在正常情况下它不应该)。当访问线程访问“to_process_count”和“当前读取pos”变量时,您必须将接收线程与处理线程/线程同步
您可以在循环缓冲区中重复使用哪些字节。
为每个所需的阅读线程创建并连接一个套接字,以便系统知道如何自行管理数据
你所引用的东西也是从单个套接字中读取的随机线程,可能通过以下场景可以实现:
1 Thread枚举socket以查看是否有可用的数据 当数据可用时,如果某个线程已处于读取状态,它会使用一些互斥锁等待启动一个新线程来读取并处理现有数据
或者可以用这样的东西来实现
一旦成功recv
(正确,数据在缓冲区中),线程就会执行recv
它从某个线程池启动另一个线程来执行recv
和继续处理数据并自行结束
Theese是我能想象的唯一方法,即“在单个插槽上读取多个线程”是可以实现的。是的,不会有多个线程同时调用recv
很抱歉这篇长篇文章,拼写和语法错误,希望这对你有所帮助
答案 1 :(得分:1)
确保套接字已正确绑定到recv
函数中使用的句柄。
除非有通道接收数据,否则无法加速数据接收。