我正在编写一个简单的 TCP 服务器,尽管我在谷歌上搜索了很多,但我无法完全弄清楚我的问题的答案。
我希望我的服务器能够处理多个客户端。
出于性能和简单性原因,我希望我的服务器是单线程的,并且我使用 select()
来处理所有套接字。
另外,我的协议是基于消息的。消息成帧是使用长度前缀完成的。 这意味着服务器需要一个缓冲区来重建一个又一个片段的消息。
最大消息长度为 64K 字节(虽然我可以将其减少到 256 字节)。
注意:这将在一个微型嵌入式设备上运行,所以使用像 ZMQ 这样的消息层不是一种选择(没有足够的内存)。
我可以:
有一个缓冲区,但这意味着一旦我开始从客户端套接字接收/重建消息,我就会忽略其他客户端套接字,直到完全接收到当前消息。这很容易受到 DOS 攻击:一个客户端发送一个巨大的消息,每字节一个字节,非常缓慢,会阻塞服务器。
每个客户端套接字有一个缓冲区,然后我的服务器将真正并行。但它不能随着客户数量的增加而很好地扩展。
是否有另一种方法可以兼具这两种技术的优点而没有缺点?
我的一个想法是使用套接字缓冲区来存储整个消息。
我会使用 setsockopt()
和 SO_RCVBUFSIZ
将缓冲区大小设置为 64K。
但我需要对 recv()
和 MSG_WAITALL
执行 MSG_DONTWAIT
,以便消息在套接字缓冲区中完全可用并且我得到它,或者它不是尚未完全接收,然后 recv()
不会阻塞。但是,这两个选项不能同时使用。
也许我可以用 recv()
做一个 MSG_PEEK
来读取大小,然后用 recv()
做另一个 MSG_PEEK
来测试是否所有字节都可用,如果是,则重新- 在没有 recv()
的情况下执行 MSG_PEEK
以实际从套接字读取字节?
无论如何,我的印象是,这是一个很早以前就必须解决的微不足道的问题。
答案 0 :(得分:1)
如果两者都可以,为什么不同时使用?
只需稍加管理,您就可以同时为多个客户端提供服务,而不会浪费宝贵的内存。
答案 1 :(得分:0)
我发现这个系列的博客非常清晰并且回答了我所有的问题:https://eli.thegreenplace.net/2017/concurrent-servers-part-1-introduction/