Socket Problems

D

Doug Jolley

I want to use a Ruby script to connect to a vendor API. I have 2
problems: 1) It takes almost a minute to establish a connection; and,
2) after the connection is finally established, no data is returned in
response to any requests. My test script which exhibits these problems
is appended as Exhibit A. As part of my investigation into these
problems, I put together a comparable PHP script. It is shown in
Exhibit B and it works perfectly (i.e., it exhibits neither of these
problems). In both scripts actual values are used for 'ip' and 'port'.
I'm really hoping that someone can tell me what I need to do to get my
Ruby script working properly. TIA.

... doug

Exhibit - Malfunctioning Ruby Script

#!/opt/ruby-enterprise-1.8.6-20090610/bin/ruby

require 'socket'
login_request=<<'_ALTO'
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<request>
<category>client</category>
<action>Login</action>
<params>
<param name="clid">135610</param>
<cltrid>135610A1276479316B171</cltrid>
<chksum>4bdee845b6e6dc67754b038f2b08bf74</chksum>
</params>
</request>
_ALTO
socket=TCPSocket::new('ip','port')
puts("Connect:\n"+socket.read()+"\n\n")
socket.print(login_request)
puts("Login:\n"+socket.read())
response=socket.read()
puts(response)
socket.close

Exhibit B - Properly Functioning Comparable PHP Script
<?php
$login_request=<<< _ALTO
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<request>
<category>client</category>
<action>Login</action>
<params>
<param name="clid">135610</param>
<cltrid>135610A1276479316B171</cltrid>
<chksum>4bdee845b6e6dc67754b038f2b08bf74</chksum>
</params>
</request>
_ALTO;
$fp=fsockopen("ip",port);
print("Connect:\n".fread($fp,1000)."\n\n");
fwrite($fp,$login_request);
print("Login:\n".fread($fp,1000));
fclose($fp);
?>
 
J

Joel VanderWerf

Doug said:
I want to use a Ruby script to connect to a vendor API. I have 2
problems: 1) It takes almost a minute to establish a connection; and,
2) after the connection is finally established, no data is returned in
response to any requests.

IO#read will read until EOF unless you tell it how many bytes to read:
puts("Connect:\n"+socket.read()+"\n\n")

as you did in php:
 
B

Brian Candler

Doug said:
require 'socket'

Socket.do_not_reverse_lookup = true # speeds things up
socket=TCPSocket::new('ip','port')
puts("Connect:\n"+socket.read()+"\n\n")

Aside: port is usually an integer not a string (unless you're giving a
service name from /etc/services)

But the main problem is that socket.read will block until the other end
drops the connection. You probably want socket.gets instead.

Other options include socket.readpartial(n) which will read *up to* n
bytes, which you may have to repeat until you have the whole response;
or if the protocol is length-framed, then use e.g. socket.read(4) to
read the length, followed by socket.read(len). But that doesn't seem to
be the case here.

I don't know the semantics of fread($fp,1000) in PHP, but from your code
I'd guess it doesn't actually wait until 1000 bytes are available, but
just reads up to 1000 bytes.

HTH,

Brian.
 
D

Doug Jolley

But the main problem is that socket.read will block until the other end
drops the connection. You probably want socket.gets instead.

Great suggestion. The problem seems to be that the xml returned by the
host (which is php based) is not terminated with a new line. In fact,
the returned xml contains no new lines at all. Consequently, using gets
produces the same result as using read.

I'm thinking that the reason I'm having problems using Ruby to interface
via a socket to a PHP based host is that each of the socket
implementations in these two languages has slightly different
expectations about the protocol being used to transmit the data. I'm
not sure what the exact differences are. As you say, it does definitely
seem that I am hung waiting for something while the PHP implementation
seems to somehow know when the host is through transmitting the data.
This hypothesis is supported by the fact that if I use readpartial and
set the number of bytes to some low value less than the length of the
data expected to be returned, I get a snappy response with the expected
bytes of data. Also of interest is the fact that I can use telnet to
interface to the PHP host and get a full response immediately. So,
apparently telnet also knows how to tell when the host is through
transmitting data.

I'm kind of surprised that there isn't more chatter on this issue. I
would think that it would have been frequently encountered by many
others before me. I do know that it's a BIG problem for me and I really
need to find a fix.
Aside: port is usually an integer not a string (unless you're
giving a service name from /etc/services)

My bad. An integer obviously correct.

Thanks to all for the input. If anyone has any further ideas, I'd sure
like to hear them.

... doug
 
D

Doug Jolley

I *FINALLY* got this issue resolved! Brian, you were definitely on the
right track with your suggestion that the 'read' method was the problem.
However, the fix was to use the 'recv' method rather than the 'gets'
method. With that fix in place everything works perfectly just like the
test PHP code. Thanks to all who contributed.

... doug
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top