网络延迟和Application->ProcessMessages()

发布于 2024-11-25 19:14:32 字数 331 浏览 1 评论 0原文

我正在编写一个在 C++Builder 项目中使用的网络 DLL。该 DLL 可与远程 FTP 服务器配合使用。我注意到调用 recv() 时出现了奇怪的行为。有时它返回 0。但是在另一个线程中,当在同一套接字上调用 recv() 时,会按预期接收数据。

这意味着什么?我还注意到,在 DLL 线程内调用 Application->ProcessMessage() 可以加快数据接收速度。

但有什么问题呢? ProcessMessages() 不只是处理窗口消息还是我遗漏了一些东西?

谢谢

I am writing a networking DLL that I use in my C++Builder project. This DLL works with remote FTP servers. I noticed a strange behavior when recv() is called. Sometimes it returns 0. But in another thread when recv() is called on the same socket, data is received as expected.

What does this mean? I also noticed that calling Application->ProcessMessage() inside the DLL thread speeds up data receiving.

But what is wrong? Doesn't ProcessMessages() just process window messages or am I missing something?

Thank you

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

清泪尽 2024-12-02 19:14:32

如果我理解正确,并且您尝试在并行线程中的同一 SOCKETrecv ,那么就不要这样做,没有任何好处。 recv 的数据已经由底层系统缓冲,并且您正在访问该数据,您可以做的就是为 recv 创建多个缓冲区,以便当它返回时您可以将一个缓冲区传递给“上层”进行处理,并将另一个缓冲区用于新的 recv 调用。您还可以仅使用一个大缓冲区,并通知哪些部分用于处理以及哪些部分用于接收。系统可能具有禁止在同一套接字上进行多次读取的锁,因此一次 recv 的结果是 0。如果没有,您可能最终会得到一些几乎随机分割的数据。

编辑:完整而长的解释

我认为使用多个线程从单个套接字读取数据没有用
套接字是一个由软件控制的东西。您的网络设备不会创建任何“连接”,它只是处理接收到的数据并将它们包装/解开到IP(或任何其他
支持的互联网层)数据包(以前取决于网络设备,其中一些几乎完全是操作系统模拟的软件,实际上只执行基本的“写入 tx-读取 rx”服务,但对我们来说是相同的交易)。 WinSock2 服务可识别包含特定数据的数据包(正如您已经注意到的那样),以便您可以同时使用一台网络设备
与多个同行进行通信。 WinSock2 在将流量分发给您之前主动监控流量。换句话说:当您即将成功接收数据时
已经存在,并且底层系统已经检查了您在 recv 中用作参数的套接字,并且只将已经标记为数据的数据交给您
对于那个插座。从一个套接字使用多个线程读取(没有几乎无用的 MSG_PEEK)将使系统(如果没有锁)复制未知数量的字节
到线程一中的 recv 中提供的位置,并根据复制的字节数永久增加指向数据的内部指针,然后,在线程 1 中可用的全部数据之前
recv 在位置 1 被复制,另一个线程将启动并复制未知数量的字节,从而也将指向数据的内部指针增加那么多字节。
理想情况下,这种类型的读取结果是从线程 1 中提供的位置存储的数据的一半,另一半从线程 2 中提供的位置开始。由于理想结果是不确定的(系统为这两个线程分配的时间不是固定的)。保证相等)你最终会得到未排序的数据,而没有任何排序方式
它,因为底层系统用于了解哪些数据属于哪个套接字的信息将无法为您提供。

由于您的系统很可能比您的网络设备更快,我支持我的两个解决方案,第一个解决方案是首选,因为我一直在使用这种方法进行大块和小块的数据传输:

  1. 为每个连接的套接字创建一个读取线程,并且一个循环缓冲区,缓冲区的大小取决于您期望接收的块的大小以及您需要进一步处理这些内容的时间,保存当前读取位置,保存“要处理的计数”,当接收到数据时通知线程/线程应该处理缓冲区中的数据,保存用于读取的数据的位置,如果有未处理的缓冲区空间,则继续 recv 否则等待直到有(必须实现此功能,以防您的计算机在某个地方卡住,在正常情况下应该这样做) t)。当接收线程访问“to_process_count”和“当前读取位置”变量时,您必须将接收线程与处理线程同步,因为它们会告诉您
    您可以在循环缓冲区中重用哪些字节。

  2. 为每个所需的读取线程创建并连接一个套接字,以便系统知道如何自行调节数据

将其称为从单个套接字读取的随机线程,这可能可以通过以下场景实现:

1 线程枚举套接字以查看是否有可用数据
当数据可用时,它使用一些互斥体来等待,如果某个线程已经处于读取状态,则启动一个新线程来读取处理现有数据

,或者可以通过类似这样的方法来实现

<一旦成功完成recv(是的,数据在缓冲区中),它就会从某个线程池启动另一个线程来执行recv > 并继续处理数据并结束自身

Theese这是我可以想象的唯一可以实现“在单个套接字上使用多个线程读取”的方法。是的,不会有多个线程同时调用 recv

抱歉,这篇文章很长,存在拼写和语法错误,希望这对您有所帮助

If I understood you correctly and you are trying to recv on the same SOCKET in parallel threads then don't do that, there is nothing to gain from it. The data you are recv is already buffered by the underlying system and you are accessing that, the thing you could do is to make multiple buffers for the recv so that when it returns data you could pass one buffer to the "upper levels" for processing and use the other one for the new recv call. You can also use just one large buffer with notifications what is for processing and what part is being used for receiving. The system probably has locks that forbid multiple reading on the same socket and so the result in one recv is 0. If it didn't have that you would probably end up with some almost randomly split data.

EDIT: Full and long explanation

I think that using multiple threads to read from a single socket is not useful
Sockets are a software regulated thing. You network device doesn't create any "connections", it just processes the data received and wraps/unwrapps them into IP (or any other
supported Internet Layer) packets (the previous depending on the network device, some of them are almost entirely software emulated by the os and actually perform just the basic "write to tx-read rx" services but to us its the same deal) . The WinSock2 service recognizes packets with specific data ( as you have already noticed ) so that you may use one network device for simultaneously
communicating with multiple peers. WinSock2 activly monitors the traffic before handing it out to you. In other words: when you are about to get a successfull recv the data
was already there and the underlying system has checked the socket you used as a parameter in recv and only handed you over the data that has already been marked as the data
for that socket. Reading with multiple threads from one socket (without the almost useless MSG_PEEK) would make the system, if it didn't have locks, copy unknown number of bytes
to the location supplied in recv in the thread one and increment the internal pointer to data by number of copied bytes permanently, then, before whole data availible in the
recv is copied at the location1, the other thread would kick in and copy also unknown number of bytes thus also incrementing the internal pointer to data by that many bytes.
Result of this type of reading would ideally be half of the data stored from location supplied in thread 1, the other half starting from location supplied in thread 2. Since the ideal result is uncertain (time allocated by the system for theese two threads is not guarantied to be equal) you would end up with unsorted data without any means of sorting
it, since the info that the underlying system uses for knowing what data belongs to which socket will not be able to you.

Being that your system is most likely faster than your network device I stand by my two solutions, first one prefered as I have been using this method for both big and small chunks of data transfer:

  1. Make one reading thread per connected socket and one circular buffer, size of the buffer depends on the size of chunks you expect to receive and the time you will need to process the stuff further, save current read position, save "to process count", when data is received notify the thread/threads that it is supposed to process the data in the buffer, save the position of the data being used for reading, continue recv if there is buffer space not being processed else wait until there is (must implement this in case your computer chokes somewhere, in normal situations it shouldn't). You must sync the receiving thread with the processing thread/threads when they are accesing the "to_process_count" and "current read pos" vars as those will tell
    you which bytes you can reuse in your circular buffer.

  2. Create and connect one socket per desired reading thread so that the system will know how to regulate the data on its own

The thing you are refering too as random threads reading from a single socket, is maybe acievable through the following scenarios:

1 Thread Enumerates socket to see if there is data availible
when data is availible it uses some mutex to wait if some thread is already in the reading state starts a new thread to read and process the existing data

or it can be achieved with something like this

Thread does its recv as soon as it has done a successful recv (yey, the data is in the buffer) it starts another thread from some thread pool to do recv and continues to process data and end itself

Theese are the only ways I can imagine that "reading with multiple threads on a single socket" is achievable. Yes, there won't be multiple threads calling recv at the same time

Sorry for the long post, the spelling and grammar errors and hope this helps you a bit

黎歌 2024-12-02 19:14:32

确保套接字正确绑定到您在 recv 函数中使用的句柄。
除非有接收数据的通道,否则无法加速数据接收。

Ensure that socket is properly bound to the handle you are using in recv function.
You cannot speedup data reception, unless there is channel to receive the data.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文