我正在开发客户端-服务器 Winsock 应用程序 (Visual C++),它应该通过网络传输各种数据(视频流、音频流、服务通知等)。我知道更简洁的方法是为每个单独的数据类型在单独的线程上使用单独的端口(我在这里称之为“流”)。但这需要占用至少 5 个不同的端口,这对于某些网络基础设施(防火墙端口转发等)会产生问题。
所以我正在尝试实现单端口连接(TCP),只有一个套接字用于传输不同的流。单个数据包将在标头中包含信息,该信息将表示它属于哪个流、预期的总消息大小等。假设我有 5 个不同的流。我打算使用 5 个线程来调用同一个套接字的send()。这安全吗?我知道来自不同流的数据包会混合到达,但如果我在每个发送的数据包中包含必要的元信息,它可以在另一端正确重建,对吧?
但真正的问题是接收端。虽然从同一个套接字上的多个线程调用send()可能是可以的(尽管我不确定并且需要您的确认!),但从多个线程调用recv()没有多大意义。所以我应该从一个线程使用一个阻塞recv() 。但是,然后,根据数据包标头(识别特定数据包属于哪个流),我应该在不同的线程中分叉处理。视频流应该由一个线程处理,声音流 - 由另一个线程处理,等等。但我不太清楚如何做到这一点 - 如何从接收线程分叉数据处理。性能是重中之重,因此不能考虑通过一个线程处理所有流。
所以总结一下,我有三个问题:
- 可以从多个线程为同一个套接字调用send()吗?(假设数据包头中有关于它属于哪个发送者线程(即子系统)的信息)。
- 在接收端有一个阻塞套接字,从单个线程循环调用recv() ,如何将不同逻辑流的接收数据包“分叉”到不同的工作线程?
- 对于通过一个端口实现多流传输,您还有什么建议?
PS:Afaik,没有办法通过多个套接字使用一个端口,对吗?
它是 Windows 平台、Winsock2、Visual C++(如果你能提供特定于平台的提示,那就太好了)。
= 更新 =
当您说“锁定套接字”时,您的意思是序列化对send()函数的访问?例如与关键部分?
至于接收端......我想我会在recv()循环时组装消息(我称“消息”为逻辑完整的数据结构,例如视频帧或声音样本等)(缓冲来自单独的流进入单独的缓冲区),然后我只是将组装的消息(当一个将被完全接收时)传递给分叉线程。现在这就是问题 - 如何通过它们。我想到的一种方法是事件对象:来自接收线程的SetEvent()来触发WaitForSingleObject()(在某个循环中)在不同的线程中。你能建议这是否是可接受的解决方案吗?你能提出更好的建议吗?没有比事件对象更快的解决方案(“触发”同一应用程序的另一个线程)吗?以及如何传递数据?