如何创建持久的TCPSockets?
我有一台服务器连续向客户端发送两条消息:
require 'socket' require 'thread' connections = [] server = TCPServer.new(9998) loop do Thread.start(server.accept) do |client| client.print 'Once' client.print 'Upon a time.' end #eo Thread end #eo infinte loop
客户是:
require 'socket' client = TCPSocket.new('localhost', 9998) 2.times { print client.read } client.close
客户端“暂停”,直到我关闭服务器,然后才打印出消息。 我知道将client.close
添加到服务器会修复暂停,但我不想关闭套接字。
我知道一些应用程序重用TCPSocket。 因此,它可以是Client > Server
, Server > Client
, Client > Server x2
,依此类推。 我相信在Ruby中有办法做到这一点; 我只是无法弄清楚如何。
所以,我的问题清单是:
- 如上所述,如何创建持久性服务器客户端连接?
- 是否有更好的方法可以在不使用
loop
情况下保持服务器打开? - 为什么它会像服务器中没有
client.close
那样保持暂停状态? 服务器在发送消息之前是否缓冲消息?
- 如上所述,如何创建持久性服务器< - >客户端连接。
你有几个选择:你可以编写一个线程服务器,其中一个主要是共享内存的“进程”执行多个执行线程,每个线程都有一些线程本地存储,例如client
。 或者,您可以编写一个多进程服务器,其中每个客户端连接通过fork(2)
获得其自己的独立进程(这几乎意味着它仅在Unix上运行,因为Windows尝试实现fork(2)
永远不会正常工作) 。 或者,您可以编写基于事件循环的状态机,并使用select(2)
或poll(2)
或epoll(4)
来管理哪些客户端是可读,可写和有错误的。
在他们之间进行选择可能看起来很困难, 但有指导方针可供选择 我想建议-small-系统,你只需要20-30个并发客户端,可以通过线程或分叉服务器很好地处理。 如果您希望超越同时数量的客户端,则应使用EventMachine或libevent等工具编写服务器。 (无论如何,这可能会或可能不会更容易维护。)
2)有没有更好的方法来保持服务器打开,而不使用循环[因为我觉得我通过创建无限循环犯下谋杀]
无限循环非常好:)但有时提供重启服务器或通过signal(7)
或专用命令接口终止它们的方法是有意义的。
3)为什么它在服务器中没有client.close的情况下保持暂停状态? 服务器在发送消息之前是否缓冲消息?
啊, 这是你真正需要的问题 – TCP将尝试缓冲来自服务器的多个数据包的结果,并且由于可能需要在路由中分割太大的数据包,作为客户端,您无法保证保留任何类型的数据报边界。
在发送第一个数据包以查看是否即将推出更多数据之前,您的服务器的TCP / IP堆栈会等待一小段机会非常好。 (它经常这样做。)它可能将对client.print()
的两次调用合并为一个TCP数据包。 您的客户端调用client.read()
两次 ,但一次读取可能只有足够的数据。 如果您希望TCP流立即发送第一个数据包,您可以查看设置TCP_NODELAY
套接字选项以禁用此小延迟。 (但它本身可能没有帮助;你可能需要与TCP_CORK
一起使用它来尝试“ TCP_CORK
”所有写入,直到你明确刷新它们。这可能是一个糟糕的主意。)
更好的选择是重新编写客户端以了解服务器和客户端之间的协议 ; 它需要将输入读入缓冲区,解析缓冲区以查找“完整消息”,使用这些消息,然后返回其主事件循环。
也许你的协议是读/写ASCII或以"\n"
字符终止的UTF-8; 在这种情况下,您可以将print
更改为puts
或将\n
添加到正确的位置,并将read()
更改为readline()
。 (这将让标准IO库为您处理协议。)另一种方法是发送长度为+数据对的数据,并等待正确的数据长度。
请改用put。 如果你想男性确定发送它,请使用socket.flush。 否则它会缓冲数据。