【问题标题】:Ruby TCPSocket write doesn't work, but puts does?Ruby TCPSocket 写入不起作用,但 puts 可以吗?
【发布时间】:2023-11-08 13:54:01
【问题描述】:

我正在使用 GServer 和 TCPSocket 开发一个 Ruby TCP 客户端/服务器应用程序。我遇到了一个我不明白的问题。我的 TCPSocket 客户端成功连接到我的 GServer,但我只能使用 puts 发送数据。对 TCPSocket.send 或 TCPSocket.write 的调用什么都不做。是不是我缺少什么魔法?

tcp_client = TCPSocket.new( ipaddr, port )
tcp_client.puts( 'Z' ) # -> GServer receives "Z\n"

但如果我使用 write 或 send...

tcp_client = TCPSocket.new( ipaddr, port )
tcp_client.write( 'Z' ) # -> nothing is received
tcp_client.send( 'Z' ) # -> nothing is received

感谢您的帮助

附加信息:

  1. Linux 和 Windows 上的行为相同。
  2. 写入后刷新套接字不会改变行为。

【问题讨论】:

    标签: ruby sockets tcp


    【解决方案1】:

    尝试显式刷新:

    tcp_client = TCPSocket.new( ipaddr, port )
    tcp_client.write( 'Z' ) 
    tcp_client.send( 'Z' ) 
    tcp_client.flush
    

    这样,输出最多只会被缓冲到您决定将其发送出去的那一点。

    【讨论】:

    • 谢谢布拉德,但请参阅我上面的评论。调用flush时没有区别。
    【解决方案2】:

    您确定问题不在服务器端吗?您是否使用某种方法来读取需要字符串或以“\n”结尾的内容?

    【讨论】:

    • 我以为我在服务器端使用了recvfrom,但结果我使用的是gets,它正在寻找换行符。
    【解决方案3】:

    在之前的帖子中处理了缓冲以解决是否正在发送数据的问题,请考虑使用wireshark 之类的方式捕获在线数据。如果在线上看到您发送的数据,则服务器没有收到它。

    否则,如果数据没有上线,TCP 可能会保留数据以避免发送其中只有几个字节的单个段 (see Nagle's Algorithm)。根据您的操作系统或 TCP 供应商,您可能会有不同的行为,但大多数 TCP 堆栈都支持 TCP_NODELAY 选项,这可能有助于更及时地获取数据。

    tcp_client.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
    

    这有助于调试,但如果吞吐量的优先级高于响应性,通常不应将其留在生产代码中。

    【讨论】:

    • netcat 也是一个非常有用的工具,用于测试目的。 "nc -v -n -l -p 12345" 将在端口 12345 上创建一个侦听服务器,该服务器将在收到数据后立即打印。
    • -l It is an error to use this option in conjunction with the -p, -s, or -z options
    【解决方案4】:

    您好,原因应该与将自动 LF 和 CRL 添加到您的字符串的事实有关。 如果您想使用 send 或 write,您需要自己添加它们,例如:

    tcp_client.send("Z\r\n",0)

    【讨论】:

      【解决方案5】:

      我遇到了同样的问题,所以在读取套接字后,我必须通过执行以下操作显式删除“\n”的最后一个实例:

      client_socket.gets.gsub(/\n$/, '')
      

      【讨论】: