Ruby TCPSocket write doesn't work, but puts does?

10,595

Solution 1

Are you sure the problem isn't on the server side? Are you using some method to read that expects a string or something ending in "\n"?

Solution 2

With buffering taken care of in previous posts to address the question of whether the data is being sent consider capturing the data on the line using something like wireshark. If the data you are sending is seen on the line then the server isn't receiving it.

Otherwise, if the data isn't going onto the line, TCP may hold onto data to avoid sending a single segment with only a few bytes in it (see Nagle's Algorithm). Depending on your OS or TCP vendor you may have different behaviour, but most TCP stacks support the TCP_NODELAY option which may help get the data out in a more timely manner.

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

This can help debugging, but typically shouldn't be left in production code if throughput is higher priority than responsiveness.

Solution 3

Try explicitly flushing:

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

This way, the output is buffered at most only until the point at which you decide it should be sent out.

Share:
10,595
nathan
Author by

nathan

I've been developing software for over 21 years using C++, C#, Java and Python. I love learning new technologies and mentoring new developers. Since I liked mentoring so much I started writing about how to help other mentors understand their students. I also write about tech, tips, and woodworking. You can find my ancient musings at Journeymandev. You can find my GitHub projects here.

Updated on August 18, 2022

Comments

  • nathan
    nathan over 1 year

    I'm working on a Ruby TCP client/server app using GServer and TCPSocket. I've run into a problem that I don't understand. My TCPSocket client successfully connects to my GServer, but I can only send data using puts. Calls to TCPSocket.send or TCPSocket.write do nothing. Is there some magic that I'm missing?

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

    But if I use write or send...

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

    Thanks for the help

    Additional information:

    1. The behavior is the same on Linux & Windows.
    2. Flushing the socket after write doesn't change the behavior.
  • nathan
    nathan almost 15 years
    Thanks brad, but see my comment above. There was no difference when calling flush.
  • Andrew Y
    Andrew Y almost 15 years
    netcat is a very useful tool as well for testing purposes. "nc -v -n -l -p 12345" will make a listening server on port 12345 that will print the data immediately as it receives it.
  • nathan
    nathan almost 15 years
    I thought I had used recvfrom for the server side, but it turned out I was using gets, which is looking for the newline character.
  • 7stud
    7stud over 10 years
    -l It is an error to use this option in conjunction with the -p, -s, or -z options