multithreading - 如何使用单个端口处理多个逻辑数据流(Winsock)?

标签 multithreading winapi visual-c++ winsock recv

我正在开发客户端-服务器 Winsock 应用程序 (Visual C++),它应该通过网络传输各种类型的数据(视频流、音频流、服务通知等)。我知道更干净的方法是为每个单独的数据类型在单独的线程上使用单独的端口(我在这里称之为“流”)。但这需要占用至少 5 个不同的端口,这会给某些网络基础设施(防火墙端口转发等)带来问题。

所以我试图实现单端口连接(TCP),只有一个套接字将用于传输不同的流。各个数据包将在 header 中包含信息,指示它属于哪个流、预期的总消息大小等。假设我有 5 个不同的流。我计划使用 5 个线程来调用同一套接字的 send() 。这安全吗?我知道来自不同流的数据包将混合到达,但如果我在每个发送的数据包中包含必要的元信息,则可以在另一端正确重建它,对吗?

但真正的问题是接收端。虽然从同一个套接字上的多个线程调用 send() 可能没问题(尽管我不确定并且需要您的确认!),但从多个线程调用 recv()线程没有多大意义。所以我应该从一个线程使用一个阻塞 recv() 。但是,然后,根据数据包 header (识别特定数据包属于哪个流),我应该在不同的线程中 fork 处理。视频流应该由一个线程处理,声音流应该由另一个线程处理,等等。但我不太知道如何做到这一点 - 如何从接收线程 fork 数据处理。性能是重中之重,因此不能考虑通过一个线程处理所有流。

总而言之,我有三个问题:

  • 可以从多个线程为同一个套接字调用 send() 吗? (假设数据包 header 中有关于其所属发送者线程(即子系统)的信息)。
  • 接收端有一个阻塞套接字,从单个线程循环调用recv(),如何将收到的不同逻辑流的数据包“fork”到不同的工作线程?
  • 对于通过一个端口实现多流传输,您有何其他建议?

P.S.:Afaik,多个套接字无法使用一个端口,对吗?

它是 Windows 平台、Winsock2、Visual C++(如果您能提供特定于平台的提示那就太棒了)。

=更新=

  • 当您说“锁定套接字”时,您的意思是序列化对 send() 函数的访问吗?例如与 Critical Section

  • 至于接收端...我想当 recv() 时我会组装消息(我将“消息”称为逻辑完整的数据结构,例如视频帧,或声音样本等) -将它们循环起来(将消息从各个流缓冲到各个缓冲区中),然后我将组装的消息(当消息被完全接收时)传递给 fork 线程。 现在的问题是 - 如何通过它们。我想到的一种方法是 Event Objects :SetEvent()从接收者线程触发不同线程中的WaitForSingleObject()(在某个循环中)。您能否建议这是否是可接受的解决方案?你能提出更好的建议吗?难道没有比事件对象更快的解决方案来执行此操作(“触发”同一应用程序的另一个线程)吗?以及如何传递数据?

最佳答案

  • Is it OK to call send() for same socket from multiple threads? (assuming there will be info in packet header about which sender thread (i.e. subsystem) it belongs).

当然你可以从多个线程调用它。但请记住,您必须在 synchronize 的套接字上加锁。它。否则,您最终可能会得到不一致的信息。

  • Having one blocking socket on the receiving end, calling recv() in loop from a single thread, how to "fork" the received packets of different logical streams to different worker threads?

如何编写类似于 boost asios 的 BeginRecv 和 EndRecv库(或切换到 Boost Asio。它是独立于平台的!)。当您收到完整的消息后,您可以将其发送出去。我想您想将其放在其他地方以便继续从网络接收信息?你可以只使用 CreateThread并通过lpParameter参数发送你的数据,这将是别人的问题而不是recv。在下载数据之前 fork 它并没有多大意义,因为您仍然需要在下一个包下载之前下载完整的包。

  • What would be your additional recommendations for implementing multiple-stream transfer through one port?

不太了解,但我写过an answer之前关于 Winsock 的内容中,我描述了 recv() 的不确定性。不要忘记同步,以确保一个包在下一个包之前写入。

When you say to "lock socket", you mean serialize the access to send() function? e.g. with Critical Section?

确实是的。您可以通过使用例如 RAII 来很好地做到这一点对于锁(然后它会在函数返回时自动删除/解锁)。但是,可以使用 sendData 函数,首先锁定对象,然后发送数据。

Now that is the question - how to pass them.

好吧,你可以将它作为一个新线程传递。

DWORD WINAPI myVideoProcessor(LPVOID theData){
    StructForKeepingVideoData* data = dynamic_cast<StructForKeepingVideoData*>(theData);
    // process the data that is passed in theData
    ...
}
...
void ReceiveData(){
    while (true){
        ...
        char buffer[SIZE];
        recv(mySocket, buffer, SIZE, 0);
        StructForKeepingVideoData* data = new StructForKeepingVideoData(buffer);

        HANDLE mId = CreateThread(NULL, 0, myVideoProcessor, data, 0, NULL);
        // now, the video processing will be done somewhere else. let's continue receiving data!
    }
}

我在这里有点模糊..但我认为你应该检查诸如auto_ptr之类的结构或shared_ptr传输数据时 - 这将帮助您销毁数据。

The one way I've thought of is Event Objects: SetEvent() from receiver thread to trigger WaitForSingleObject() (which is in some loop) in different threads. Can you advice if this is the acceptable solution?

事件也可以,但这不是我冒险尝试的事情。然后你就可以让你的线程一直运行,而不是在有数据要处理时启动。 记住您还必须保持数据传输同步。如果您有某种队列,则必须确保写入和读取相继完成。

Can you suggest anything better? Aren't there any faster solutions to do this ("trigger" another thread of the same application) than Event Objects? And how to pass the data?

不知道有什么更快。但要传递数据,要么在创建线程时执行,要么使用某种保持同步的队列。

希望这有帮助。

关于multithreading - 如何使用单个端口处理多个逻辑数据流(Winsock)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6331003/

相关文章:

c# - 如何在 Xamarin.Forms 中制作平滑移动的音频 slider

c++ - C++多线程并发向单个MySQL表插入数据

c - 如何对在 Windows 中复制文件的最快方法进行基准测试(内存映射与文件 I/O)

c++ - 无法将 FindFileData.cFileName 转换为字符串

multithreading - 无法从编程书上运行我的代码(c++)

c++ - 为什么我得到 "vector iterators incompatible"?

java.lang.RuntimeException : Only one Looper may be created per thread

java - 如何在 SWING 中执行时停止代码块

c++ - 有没有办法使用 WINAPI 或 Embarcadero C++ Builder XE 创建共享目录/文件夹?

c++ - VC++ 异常处理 - 应用程序无论如何都会崩溃