【问题标题】:How do I create persistant TCPSockets?如何创建持久 TCP 套接字?
【发布时间】:2011-05-27 22:16:37
【问题描述】:

我有一个服务器连续向客户端发送两条消息:

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 > ServerServer > ClientClient > Server x2,等等。我确信在 Ruby 中有一种方法可以做到这一点。我就是想不通。

所以,我的问题清单是:

  1. 如何创建持久服务器 如上所述的客户端连接?
  2. 有没有更好的方法在不使用loop 的情况下保持服务器打开?
  3. 为什么在服务器中没有client.close 时它会一直保持挂起状态?服务器在发送消息之前是否对消息进行缓冲?

【问题讨论】:

    标签: ruby sockets


    【解决方案1】:
    1. 如何创建持久服务器 客户端连接,如上所述。

    您有多种选择:您可以编写一个线程服务器,其中一个具有大部分共享内存的“进程”执行多个执行线程,并且每个线程都有一些线程本地存储,例如client。或者,您可以编写一个多进程服务器,其中每个客户端连接通过fork(2) 获得自己的独立进程(这几乎意味着它仅在 Unix 上运行,因为 Windows 试图实现 fork(2) 永远无法正常工作)。或者,您可以编写一个基于事件循环的状态机,并使用select(2)poll(2)epoll(4) 来管理哪些客户端是可读、可写和有错误的。

    在它们之间做出选择似乎很困难,but there are guidelines available。我想建议您可以通过线程或分叉服务器很好地处理-small-系统,您预计只有20-30 个并发客户端。如果您希望超过该数量的同时客户端,您应该使用EventMachinelibevent 之类的工具来编写您的服务器。 (无论如何,这可能更容易维护,也可能不容易维护。)

    2) 有没有更好的方法来保持服​​务器打开而不使用循环[因为我觉得我通过创建无限循环犯下了谋杀罪]

    无限循环非常好:) 但有时提供一种方法来重新启动服务器或通过signal(7)s 或专用命令接口终止它们是有意义的。

    3) 为什么在服务器中没有 client.close 的情况下它会一直保持挂起状态?服务器在发送消息之前是否缓冲消息?

    啊,这里是你真正需要的问题——TCP将尝试缓冲来自服务器的多个数据包的结果,并且由于可能需要分段如果数据包中途太大,作为客户端,您无法保证保留任何类型的数据报边界。

    很有可能非常您的服务器的 TCP/IP 堆栈在发送第一个数据包之前稍等片刻以查看是否有更多数据即将到来。 (它经常这样做。)它可能会将 两个client.print() 的调用合并为一个 TCP 数据包。您的客户调用client.read()两次,但可能只有足够的数据供一次读取。如果您希望您的 TCP 流立即发送第一个数据包,您可以考虑设置 TCP_NODELAY 套接字选项来禁用这个小延迟。 (但它本身可能无济于事;您可能需要将它与 TCP_CORK 结合使用以尝试“封存”所有写入,直到您明确刷新它们。这可能是一个糟糕的主意。)

    更好的选择是重写您的客户端以了解您的服务器和客户端之间的协议;它需要将输入读入缓冲区,解析缓冲区以找到“完整消息”,使用这些消息,然后返回其主事件循环。

    也许您的协议是读取/写入以"\n" 字符结尾的ASCII 或UTF-8;在这种情况下,您可以将print 更改为puts 或在正确的位置添加\n,然后将read() 更改为readline()。 (这将使标准 IO 库为您处理您的协议。)另一种方法是使用长度+数据对发送数据,并等待正确的数据长度。

    【讨论】:

    • 我必须说,阅读您的回复既有趣又足智多谋且有用。谢谢
    • @with a dot.,谢谢 :) 我特别喜欢I feel like I've committed murder by creating an endless loop。 :)
    【解决方案2】:

    使用 puts 代替。如果你想确定它已发送,请使用 socket.flush 。否则它会缓冲数据。

    【讨论】:

    • 如果我想使用二进制传输怎么办(考虑到这一点;我是个疯子)。那么打印不是更好的选择吗?另外,(也许我错了,关于我要说的)会用puts阅读工作吗?我不必使用gets吗?欧:
    • socket.sync=true 或每次写入后刷新。
    猜你喜欢
    • 2017-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    • 2015-08-01
    • 2014-02-07
    • 2011-10-26
    • 2010-09-07
    相关资源
    最近更新 更多