0

I've this Ruby server that uses a Unix Socket:

require 'socket'

server = UNIXServer.new('/tmp/ciccio.sock')
loop do
  sock = server.accept
  loop do
    begin
      data = sock.recv(1024)
      data = "DO SOMETHING -> #{data}"
      sock.write(data)
      sock.flush
    rescue Errno::EPIPE, Errno::ENOTCONN
      break
    end
  end
end

And I've this client in JavaScript that uses node.js net api:

Net = require('net');

var client = Net.connect({path: '/tmp/ciccio.sock'}, () => {
  console.log('write data');
  client.write('hello world!');
});

client.on('data', (data) => {
  console.log(data.toString());
  client.end();
});

client.on('end', () => {
  console.log('end');
});

client.on('error', (error) => {
  console.log(error.toString());
});

The problem is that at the first iteration of server loop, recv receives the right string and the server replies to the client with the string data. But at the second iteration recv receives empty data and so a infinite loop begins... server continues to receive empty data and recv does not block...

If I use a ruby client like this all works fine...

require 'socket'

sock = UNIXSocket.new('/tmp/ciccio.sock')
loop do
  sock.write('hello world!')
  data = sock.recv(1024)
  puts data
  sleep(10)
end
sock.close
4
  • Why do you call client.end(); on data? Should not it be called on end instead? Commented Nov 25, 2015 at 12:57
  • @mudasobwa I've used the example of the doc nodejs.org/api/net.html#net_net_connect_options_connectlistener Commented Nov 25, 2015 at 13:00
  • The problem is that recv doesn't block, so it can only return what's available at that instant, which is sometimes nothing. W. Richard Stevens is the authority on this. Read his book Commented Nov 25, 2015 at 13:21
  • 1
    @JohnLaRooy recv is a blocking call while recv_nonblock is the non-blocking variant. Of course, this assumes the file descriptor was not set with O_NONBLOCK prior to calling recv. I'm willing to bet that this is not the case and that recv is blocking but after the connection finishes, recv is being called on a closed socket and therefore will always return an empty string. Commented Nov 25, 2015 at 18:54

1 Answer 1

2

Your client closes the connection upon connecting, writing "hello world", and then receiving a response. Now your server is calling recv on a socket that has been closed, which will return an empty string. Since you're looping to read on this socket indefinitely, it will never return control back to the outer loop to call accept for the second client. The ruby version of your client works because it never closes the connection to the server.

Breaking out of your inner loop after receiving an empty string should get you what you want,

require 'socket'

server = UNIXServer.new('/tmp/ciccio.sock')
loop do
  sock = server.accept
  loop do
    begin
      data = sock.recv(1024)
      break if data.empty?

      data = "DO SOMETHING -> #{data}"
      sock.write(data)
      sock.flush
    rescue Errno::EPIPE, Errno::ENOTCONN
      break
    end
  end
end

Another potential problem is that your server can only service a single connection to a single client, as the inner loop blocks any subsequent calls to accept until the current connection ends.

Sign up to request clarification or add additional context in comments.

1 Comment

"Now your server is calling recv on a socket that has been closed, which will return an empty string": this was the part I did not understand. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.