处理多个 TCP 客户端
Handle multiple TCP clients
我正在编写一个简单的 TCP 服务器,尽管进行了很多谷歌搜索,但我还是无法完全找出我的问题的答案。
我希望我的服务器处理多个客户端。
出于性能和简单的原因,我希望我的服务器是单线程的,并且我使用 select()
来处理所有套接字。
此外,我的协议是基于消息的。消息框架是使用长度前缀完成的。
这意味着服务器需要一个缓冲区来逐个片段地重建消息片段。
最大消息长度为 64K 字节(尽管我可以将其减少到 256 字节)。
注意:这将在微型嵌入式设备上 运行,因此不能选择使用像 ZMQ 这样的消息传递层(内存不足)。
我可以:
只有一个缓冲区,但这意味着一旦我开始 receive/reconstruct 来自客户端套接字的消息,我将忽略其他客户端套接字,直到完全接收到当前消息。这很容易受到 DOS 攻击:一个客户端发送一个巨大的消息,一个字节一个字节,速度非常慢,会阻塞服务器。
每个客户端套接字有一个缓冲区,这样我的服务器就会真正并行。但它不能很好地适应客户端数量。
是否有另一种方法既有这两种技术的优点又具有 none 的缺点?
我的一个想法是使用套接字缓冲区来存储整个消息。
我会使用 setsockopt()
和 SO_RCVBUFSIZ
.
将缓冲区大小设置为 64K
但我需要对 MSG_WAITALL
和 MSG_DONTWAIT
执行 recv()
,以便消息在套接字缓冲区中完全可用并且我得到它,或者它尚未完全收到,然后 recv()
不会阻止。但是,这两个选项不能一起使用。
也许我可以做一个 recv()
和 MSG_PEEK
来读取大小,然后另一个 recv()
和 MSG_PEEK
来测试是否所有字节都可用,如果是的话然后在没有 MSG_PEEK
的情况下重新执行 recv()
以实际从套接字读取字节?
总之,我的印象是一个小问题,肯定早就解决了。
如果可以两者兼得,为什么不同时使用呢?
- 为 'few' 个客户提供一个大的缓冲区。
- 保持每个客户端读取之间的时间,如果您认为存在 DOS 攻击或读取需要很长时间(由于连接速度慢),请将客户端踢开。这里的思路是实现一个时间window.
- 如果您处于 'prime time',请增加缓冲区(针对更多客户)或分配另一个缓冲区(基于银行)。
- 否则缩小缓冲区。
只需一点管理,您就可以同时为多个客户提供服务,而不会浪费宝贵的内存。
我找到了这个系列的博客,我觉得很清楚,并回答了我所有的问题:https://eli.thegreenplace.net/2017/concurrent-servers-part-1-introduction/
我正在编写一个简单的 TCP 服务器,尽管进行了很多谷歌搜索,但我还是无法完全找出我的问题的答案。
我希望我的服务器处理多个客户端。
出于性能和简单的原因,我希望我的服务器是单线程的,并且我使用 select()
来处理所有套接字。
此外,我的协议是基于消息的。消息框架是使用长度前缀完成的。 这意味着服务器需要一个缓冲区来逐个片段地重建消息片段。
最大消息长度为 64K 字节(尽管我可以将其减少到 256 字节)。
注意:这将在微型嵌入式设备上 运行,因此不能选择使用像 ZMQ 这样的消息传递层(内存不足)。
我可以:
只有一个缓冲区,但这意味着一旦我开始 receive/reconstruct 来自客户端套接字的消息,我将忽略其他客户端套接字,直到完全接收到当前消息。这很容易受到 DOS 攻击:一个客户端发送一个巨大的消息,一个字节一个字节,速度非常慢,会阻塞服务器。
每个客户端套接字有一个缓冲区,这样我的服务器就会真正并行。但它不能很好地适应客户端数量。
是否有另一种方法既有这两种技术的优点又具有 none 的缺点?
我的一个想法是使用套接字缓冲区来存储整个消息。
我会使用 setsockopt()
和 SO_RCVBUFSIZ
.
但我需要对 MSG_WAITALL
和 MSG_DONTWAIT
执行 recv()
,以便消息在套接字缓冲区中完全可用并且我得到它,或者它尚未完全收到,然后 recv()
不会阻止。但是,这两个选项不能一起使用。
也许我可以做一个 recv()
和 MSG_PEEK
来读取大小,然后另一个 recv()
和 MSG_PEEK
来测试是否所有字节都可用,如果是的话然后在没有 MSG_PEEK
的情况下重新执行 recv()
以实际从套接字读取字节?
总之,我的印象是一个小问题,肯定早就解决了。
如果可以两者兼得,为什么不同时使用呢?
- 为 'few' 个客户提供一个大的缓冲区。
- 保持每个客户端读取之间的时间,如果您认为存在 DOS 攻击或读取需要很长时间(由于连接速度慢),请将客户端踢开。这里的思路是实现一个时间window.
- 如果您处于 'prime time',请增加缓冲区(针对更多客户)或分配另一个缓冲区(基于银行)。
- 否则缩小缓冲区。
只需一点管理,您就可以同时为多个客户提供服务,而不会浪费宝贵的内存。
我找到了这个系列的博客,我觉得很清楚,并回答了我所有的问题:https://eli.thegreenplace.net/2017/concurrent-servers-part-1-introduction/