C++套接字 Send() 线程安全
我正在为最多 1000 个客户端编写套接字服务器,该服务器与我的游戏有关,我使用非阻塞套接字和大约 10 个线程,它们同时从不同套接字接收数据(第一个线程从 0-100 接收,第二个线程从 101-200 接收数据)等等..)
但是如果线程 1 想要向所有 1000 个客户端发送数据,而线程 2 也想同时向所有 1000 个客户端发送数据,这样安全吗?数据在另一端(客户端)是否有可能被弄乱?
如果是,我想可能发生的唯一问题是有时客户端会收到 2 或 10 个数据包作为 1 个数据包,这是正确的吗?如果是的话,有什么解决办法吗:(
I am coding sockets server for 1000 clients maxmimum, the server is about my game, i'm using non-blocking sockets and about 10 threads that receive data simultaneously from different sockets (first thread receives from 0-100,second from 101-200 and so on..)
but if thread 1 wants to send data to all 1000 clients and thread 2 also wants to send data to all 1000 clients at the same time, is that safe? are there any chances of the data being messed in the other (client) side?
if yes, i guess the only problem that can happen is that sometimes client would receive 2 or 10 packets as 1 packet, is that correct? if yes, is there any solution to that :(
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
处理许多套接字的通常模式是使用专用线程轮询 I/O 事件 <代码>选择(2),
轮询(2)
,或者更好kqueue(2)
或epoll(4)
(取决于平台)充当套接字事件调度程序。套接字通常以非阻塞模式处理。然后,可能会有一组线程对事件做出反应,并且直接或通过较低级别的缓冲区/队列进行读取和写入。
从队列到事件订阅白板,各种技术都适用于此。在 I/O 级别上复用接受/读取/写入/EOF 以及在应用程序级别上进行事件仲裁会变得很棘手。几个库,例如
libevent
和 < a href="http://www.boost.org/doc/libs/1_43_0/doc/html/boost_asio.html" rel="nofollow noreferrer">boost::asio< /code> 帮助构建较低级别(ACE 库也在这个空间中,但我不想向任何人推荐它)。您必须自己提出应用程序级协议和状态机(再次
boost::statechart
可能会有所帮助)。一些很好的链接可以更好地了解您所面临的问题(这可能是他们在这里提到的第一百万次):
很抱歉没有提供具体的解决方案,但这是一个非常广泛的设计问题,大多数决策在很大程度上取决于上下文(尽管很有趣)。希望这会有所帮助。
The usual pattern of dealing with many sockets is to have a dedicated thread polling for I/O events with
select(2)
,poll(2)
, or betterkqueue(2)
orepoll(4)
(depending on the platform) acting as socket event dispatcher. The sockets are usually handled in non-blocking mode. Then one might have pool of threads reacting to the events and either do reads and writes directly or via lower level buffers/queues.All sorts of techniques are applicable here - from queues to event subscription whiteboards. It gets tricky with multiplexing accepts/reads/writes/EOFs on the I/O level and with event arbitration on the application level. Several libraries like
libevent
andboost::asio
help structure the lower level (the ACE library is also in this space, but I'd hate recommending it to anybody). You would have to come up with application-level protocols and state machines yourself (againboost::statechart
might be of help).Some good links to get better understanding of what you are up against (this is probably the millionth time they are mentioned here on SO):
Apologies for not offering a concrete solution, but this is a very wide design question and most decisions depend heavily on the context (lots of fun though). Hope this helps a bit.
由于您使用不同的套接字发送数据,因此一定不会有任何问题。相反,当这些不同的线程访问相同的数据时,您必须确保数据完整性。
Since you are sending data using different sockets, there must not be any problem. Rather when these different threads access same data you have to ensure data integrity.
您使用的是 UDP 还是 TCP 套接字?
如果是UDP,每次写入都应该封装在一个单独的数据包中,并且应该完整地传送到另一端。顺序可以交换(对于任何 UDP 数据包都可以),但它们应该是完整的。
如果是 TCP,则传输层上没有数据包的概念,一侧的任何 10 次写入可能会在一次读取中捆绑到另一侧。 TCP 写入也可能只接受缓冲区的一部分,因此即使 send() 函数是原子的,您的写入也不一定。在这种情况下,您需要对其进行同步。
Are you using UDP or TCP sockets?
If UDP, each write should be encapsulated in a separate packet and should be carried to the other side intact. The order may be swapped (as it may for any UDP packet) but they should be whole.
If TCP, there's no concept of packets on the transport layer and any 10 writes on one side may be bundled up on the other side in one read. TCP writes may also only accept part of your buffer so even if the send() function is atomic, your write isn't necessarily. In this case you'd need to synchronize it.
send() 在大多数实现中都不是原子的,因此从多个线程发送到 1000 个不同的套接字可能会导致到达客户端的消息混合,以及各种奇怪的情况。(I什么都不知道,请参阅下面的 Nicolai 和 Robert 的评论,尽管我的评论的其余部分仍然有效(就解决您的问题而言)))我要做的是使用线程进行发送,就像您使用它们进行接收一样。一个线程管理向一个(或多个)套接字的发送,确保您不会同时从多个线程写入一个套接字。
另请参阅此处以获取一些其他讨论和更有趣的链接。
如果您使用的是 Windows,winsock 程序员常见问题解答 是非常宝贵的资源,对于您的问题,请参阅此处。
send() is not atomic in most implementations, so sending to 1000 different sockets from multiple threads could lead to mixed-up messages arriving on the client side, and all kinds of weirdness.(I know nothing, see Nicolai's and Robert's comments below the rest of my comment still stands though (in terms of being a solution to your problem))What I would do is use threads for sending like you use them for receiving. One thread to manage sending to one (or more) sockets that ensures that you don't write to one socket from multiple threads at the same time.
Also look here for some additional discussion and more interesting links.
If you're on windows, the winsock programmers faq is an invaluable resource, for your issue see here.