Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > client server socket interaction (inetd)

Reply
Thread Tools

client server socket interaction (inetd)

 
 
Tim
Guest
Posts: n/a
 
      02-17-2011
Hi, I have an inetd service on freebsd that calls a program
(daemon.py) with which I want the remote user to communicate. I can
call daemon.py from the command line on the host machine and it works
fine.

What I don't understand is how to make my remote client script
actually communicate. If I'm understanding correctly, the code below
just takes a message and sends it to inetd and writes the stdout from
the process to the client.

How can I modify the code to send a response back? Here's the
outline of what I want to do:
(1) client sends the message to the server (client -> inetd ->
daemon.py),
(2) client receives output back from the server,
(3) client user responds to a question from the remote process
(4) client continues to receive output back.

where 2-3-4 happen as needed by the remote process. Cries out for a
while loop doesn't it? I just don't know what to put in it. Currently
I just have steps 1 and 2 working. Client sends one message and gets
all output back. If server asks a question, processes deadlock with
server waiting and client unable to respond.
thanks,
--Tim Arnold

# imports, constants set
#def line_buffer(sock):
# code to yield the string response in
# blocks of 1024 bytes

def client(ip,port,message):
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((ip,port))
sock.send(message)
for line in line_buffer(sock):
print line
sock.close()

if __name__ == '__main__':
message = ' '.join(sys.argv[1:]) )
print 'working... %s %s' % (SERVER_IP,SERVER_PORT)
client(SERVER_IP,SERVER_PORT,message)
print 'done.'


 
Reply With Quote
 
 
 
 
Martin Gregorie
Guest
Posts: n/a
 
      02-17-2011
On Thu, 17 Feb 2011 08:14:36 -0800, Tim wrote:

> Hi, I have an inetd service on freebsd that calls a program (daemon.py)
> with which I want the remote user to communicate. I can call daemon.py
> from the command line on the host machine and it works fine.
>
> What I don't understand is how to make my remote client script actually
> communicate. If I'm understanding correctly, the code below just takes a
> message and sends it to inetd and writes the stdout from the process to
> the client.
>
> How can I modify the code to send a response back?
>

The code you've shown would appear to be doing what you've specified,
though only you can know whether this is what you intended.
Each time you run the client it:
- connects to the server
- sends a request
- reads the response(s)
- closes the socket and exits.

If you run it a second time it should do the same again. Is this the case?

An inetd server should be started when a connection request is received.
It should read requests, sending a response to each request in turn,
until the connection is closed, when it will be stopped by inetd.

Without seeing the code for the server and the corresponding inetd
configuration line its not possible to say more.

BTW, I prefer xinetd to inetd - its configuration is much more modular
and easier to understand. If freebsd supports xinetd it may make life
easier if you use it rather than inetd.



Here's the outline
> of what I want to do:
> (1) client sends the message to the server (client -> inetd ->
> daemon.py),
> (2) client receives output back from the server, (3) client user
> responds to a question from the remote process (4) client continues to
> receive output back.
>
> where 2-3-4 happen as needed by the remote process. Cries out for a
> while loop doesn't it? I just don't know what to put in it. Currently I
> just have steps 1 and 2 working. Client sends one message and gets all
> output back. If server asks a question, processes deadlock with server
> waiting and client unable to respond. thanks,
> --Tim Arnold
>
> # imports, constants set
> #def line_buffer(sock):
> # code to yield the string response in # blocks of 1024 bytes
>
> def client(ip,port,message):
> sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
> sock.connect((ip,port))
> sock.send(message)
> for line in line_buffer(sock):
> print line
> sock.close()
>
> if __name__ == '__main__':
> message = ' '.join(sys.argv[1:]) )
> print 'working... %s %s' % (SERVER_IP,SERVER_PORT)
> client(SERVER_IP,SERVER_PORT,message) print 'done.'




--
martin@ | Martin Gregorie
gregorie. | Essex, UK
org |
 
Reply With Quote
 
 
 
 
bobicanprogram
Guest
Posts: n/a
 
      02-17-2011
On Feb 17, 2:41 pm, Martin Gregorie <(E-Mail Removed)>
wrote:
> On Thu, 17 Feb 2011 08:14:36 -0800, Tim wrote:
> > Hi, I have an inetd service on freebsd that calls a program (daemon.py)
> > with which I want the remote user to communicate. I can call daemon.py
> > from the command line on the host machine and it works fine.

>
> > What I don't understand is how to make my remote client script actually
> > communicate. If I'm understanding correctly, the code below just takes a
> > message and sends it to inetd and writes the stdout from the process to
> > the client.

>
> > How can I modify the code to send a response back?

>
> The code you've shown would appear to be doing what you've specified,
> though only you can know whether this is what you intended.
> Each time you run the client it:
> - connects to the server
> - sends a request
> - reads the response(s)
> - closes the socket and exits.
>
> If you run it a second time it should do the same again. Is this the case?
>
> An inetd server should be started when a connection request is received.
> It should read requests, sending a response to each request in turn,
> until the connection is closed, when it will be stopped by inetd.
>
> Without seeing the code for the server and the corresponding inetd
> configuration line its not possible to say more.
>
> BTW, I prefer xinetd to inetd - its configuration is much more modular
> and easier to understand. If freebsd supports xinetd it may make life
> easier if you use it rather than inetd.
>
> Here's the outline
>
>
>
> > of what I want to do:
> > (1) client sends the message to the server (client -> inetd ->
> > daemon.py),
> > (2) client receives output back from the server, (3) client user
> > responds to a question from the remote process (4) client continues to
> > receive output back.

>
> > where 2-3-4 happen as needed by the remote process. Cries out for a
> > while loop doesn't it? I just don't know what to put in it. Currently I
> > just have steps 1 and 2 working. Client sends one message and gets all
> > output back. If server asks a question, processes deadlock with server
> > waiting and client unable to respond. thanks,
> > --Tim Arnold

>
> > # imports, constants set
> > #def line_buffer(sock):
> > # code to yield the string response in # blocks of 1024 bytes

>
> > def client(ip,port,message):
> > sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
> > sock.connect((ip,port))
> > sock.send(message)
> > for line in line_buffer(sock):
> > print line
> > sock.close()

>
> > if __name__ == '__main__':
> > message = ' '.join(sys.argv[1:]) )
> > print 'working... %s %s' % (SERVER_IP,SERVER_PORT)
> > client(SERVER_IP,SERVER_PORT,message) print 'done.'

>
> --
> martin@ | Martin Gregorie
> gregorie. | Essex, UK
> org |



Have a look at the SIMPL toolkit (http://www.icanprogram.com/06py/
lesson1/lesson1.html). It will allow you to do exactly what you want
without having to dive into socket programming.

bob
 
Reply With Quote
 
Tim
Guest
Posts: n/a
 
      02-17-2011
On Feb 17, 2:41*pm, Martin Gregorie <(E-Mail Removed)>
wrote:
> On Thu, 17 Feb 2011 08:14:36 -0800, Tim wrote:
> > Hi, I have an inetd service on freebsd that calls a program (daemon.py)
> > with which I want the remote user to communicate. *I can call daemon.py
> > from the command line on the host machine and it works fine.

>
> > What I don't understand is how to make my remote client script actually
> > communicate. If I'm understanding correctly, the code below just takes a
> > message and sends it to inetd and writes the stdout from the process to
> > the client.

>
> > How can I modify the code to send a response back?

>


> --
> martin@ * | Martin Gregorie
> gregorie. | Essex, UK
> org * * * |


Thanks Martin, you're right:

> Each time you run the client it:
> - connects to the server
> - sends a request
> - reads the response(s)
> - closes the socket and exits.


that is exactly what it's doing. But. The server may encounter a
problem during the process and ask the user for more information like
'abort/retry' or something like that.

What my code does *not* do is allow the user to respond to such a mid-
process question (so the server can take in that information and
proceed with its process). The server can ask, but there's no
mechanism for the user to respond to a question.

> Without seeing the code for the server and the corresponding inetd
> configuration line its not possible to say more.


I'm not trying to be opaque, but the reason I left out the code for
the server (daemon.py) is that it works as expected when exec'd from
the command line. That is, the process begins, asks a question, gets
an answer and continues.

The inetd configuration is:
myservice stream tcp nowait root /local/daemon.py daemon.py
 
Reply With Quote
 
Martin Gregorie
Guest
Posts: n/a
 
      02-17-2011
On Thu, 17 Feb 2011 13:02:08 -0800, Tim wrote:

> But. The server may encounter a problem
> during the process and ask the user for more information like
> 'abort/retry' or something like that.
>

Servers never ask the client for information: they are strictly request/
response handlers. To do what you're asking about, you'll need to change
both the client and server:

- the client must analyse every response and, if necessary, ask for
more input from the user. IMO it would be best to design it so it
can accept several commands, with 'quit' being one of them. Either
that or all request/response pairs must be designed so that the client
can always send a single request, output the result and exit no matter
what the server returns.

- the server must always return a response to every possible request
or log a failure reason, preferably to the system log which is
/var/log/messages in Linux, and die. The server must thoroughly
validate requests and return an adequate error message if errors were
found. I'd strongly suggest that every request generates a single
(newline terminated?) response message because that makes error
detection much easier. If the response is multi-line, send it as a
single line, possibly as a comma-separated list, and let the client
format it for display

I tend to precede every request and response message with a fixed length
byte count: this way the recipient process always knows how many bytes to
read and can report errors if the received length is wrong. Using an 'end
of message marker' (NEWLINE unless a message can legally contain internal
newlines) can also be useful. I tend to put an error flag in the response
message because this simplifies the client. I also design all messages to
be plain ASCII because this makes debugging a lot easier. If things
really turn to worms you can use wireshark to watch the traffic and read
it straight off the screen without needing to decode binary values, etc.
So, an invalid request and response might look like this:

Request: "0013,WHOIS,elvis\n"
Response: "0030,ERROR,Unknown request: WHOIS\n"

> The inetd configuration is:
> myservice stream tcp nowait root /local/daemon.py daemon.py
>

From what I recall about inetd that should be OK - I guess it must be
since you can get one request through, and I assume (you didn't say) that
a second request is also accepted without restarting the server.


--
martin@ | Martin Gregorie
gregorie. | Essex, UK
org |
 
Reply With Quote
 
Tim
Guest
Posts: n/a
 
      02-18-2011
On Feb 17, 6:09*pm, Martin Gregorie <(E-Mail Removed)>
wrote:
> On Thu, 17 Feb 2011 13:02:08 -0800, Tim wrote:
> > But. The server may encounter a problem
> > during the process and ask the user for more information like
> > 'abort/retry' or something like that.

>
> Servers never ask the client for information: they are strictly request/
> response handlers. To do what you're asking about, you'll need to change
> both the client and server:
>
> - the client must analyse every response and, if necessary, ask for
> * more input from the user. IMO it would be best to design it so it
> * can accept several commands, with 'quit' being one of them. Either
> * that or all request/response pairs must be designed so that the client
> * can always send a single request, output the result and exit no matter
> * what the server returns.
>
> - the server must always return a response to every possible request
> * or log a failure reason, preferably to the system log which is
> * /var/log/messages in Linux, and die. The server must thoroughly
> * validate requests and return an adequate error message if errors were
> * found. I'd strongly suggest that every request generates a single
> * (newline terminated?) response message because that makes error
> * detection much easier. If the response is multi-line, send it as a
> * single line, possibly as a comma-separated list, and let the client
> * format it for display
>
> I tend to precede every request and response message with a fixed length
> byte count: this way the recipient process always knows how many bytes to
> read and can report errors if the received length is wrong. Using an 'end
> of message marker' (NEWLINE unless a message can legally contain internal
> newlines) can also be useful. I tend to put an error flag in the response
> message because this simplifies the client. I also design all messages to
> be plain ASCII because this makes debugging a lot easier. If things
> really turn to worms you can use wireshark to watch the traffic and read
> it straight off the screen without needing to decode binary values, etc.
> So, an invalid request and response might look like this:
>
> Request: * "0013,WHOIS,elvis\n"
> Response: *"0030,ERROR,Unknown request: WHOIS\n"
>
> > The inetd configuration is:
> > myservice *stream tcp nowait root /local/daemon.py daemon.py

>
> From what I recall about inetd that should be OK - I guess it must be
> since you can get one request through, and I assume (you didn't say) that
> a second request is also accepted without restarting the server.
>
> --
> martin@ * | Martin Gregorie
> gregorie. | Essex, UK
> org * * * |


Thanks for helping me to understand. I don't know if you're familiar
with LaTeX, but that's part of what daemon.py calls via subprocess,
and that is the underlying process I wanted the user to be able to
interact with.

When LaTeX encounters a problem it stops processing, asks the user
what to do (like abort/retry, kind-of), and does whatever the user
says. The daemon.py script handles that okay from the command line,
but if I'm understanding you this will be much harder if not
impossible to accomplish from a client communicating over a socket.

I thought that maybe I needed to fork the socket (somehow) so it could
listen after the message is sent, but it looks like it will be more
complex.

thanks, I'm going to back to reading more on socket programming.
--Tim
 
Reply With Quote
 
Martin Gregorie
Guest
Posts: n/a
 
      02-18-2011
On Fri, 18 Feb 2011 07:23:35 -0800, Tim wrote:

> Thanks for helping me to understand. I don't know if you're familiar
> with LaTeX, but that's part of what daemon.py calls via subprocess, and
> that is the underlying process I wanted the user to be able to interact
> with.
>

I've used nroff but never LaTeX - however, my understanding is that its
essentially a batch process.

> When LaTeX encounters a problem it stops processing, asks the user what
> to do (like abort/retry, kind-of), and does whatever the user says. The
> daemon.py script handles that okay from the command line, but if I'm
> understanding you this will be much harder if not impossible to
> accomplish from a client communicating over a socket.
>

Are you sure it wouldn't be better to end the run, returning suitable
error messages to the user, who would correct the input file(s) and rerun
LaTex?

> I thought that maybe I needed to fork the socket (somehow) so it could
> listen after the message is sent, but it looks like it will be more
> complex.
>

The easier way my be to give the user a login to a captive shell that's
restricted to running LateX, an editor and little else apart from a
results viewer. Bash and most decent editors can be restricted so the
user can't start a second, less restricted shell, and the range of
programs it can execute can be restricted by adjusting with $PATH.

You may also be able to find a menu program that can impose many of those
restrictions by replacing the login's shell by the menu program. I do
this as a matter of course: my menu program may get released one of these
days but it's not currently on a fit state to publish.

If you want to continue down the server path you should investigate popen.
It is part of the os module. You could design the server so a suitable
request runs LaTeX via popen, captures the stdout and stderr output, if
any, and returns that and the LaTeX termination status code to the client
as a response message.


--
martin@ | Martin Gregorie
gregorie. | Essex, UK
org |
 
Reply With Quote
 
Nobody
Guest
Posts: n/a
 
      02-18-2011
On Fri, 18 Feb 2011 07:23:35 -0800, Tim wrote:

> When LaTeX encounters a problem it stops processing, asks the user
> what to do (like abort/retry, kind-of), and does whatever the user
> says. The daemon.py script handles that okay from the command line,
> but if I'm understanding you this will be much harder if not
> impossible to accomplish from a client communicating over a socket.


The difficulty of achieving this is unrelated to the use of a socket. It's
an issue of whether you have a user available to respond to any prompts,
or whether the client has to be able to do this itself.

If you want to "script" an interactive program, you need to be able to
recognise prompts and respond appropriately. If the program was designed
to interact with a human, this can be far from straightforward. But the
method of communication (pipes versus sockets) isn't relevant.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
simple socket client-server interaction works on C, but the analogouscode does not work with Perl Mark_Galeck Perl Misc 3 08-16-2009 06:59 PM
socket.unbind or socket.unlisten? - socket.error: (48, 'Addressalready in use') Laszlo Nagy Python 1 01-27-2009 05:05 PM
Re: socket.unbind or socket.unlisten? - socket.error: (48,'Address already in use') Jean-Paul Calderone Python 0 01-27-2009 01:41 PM
writing data form server socket to client socket greatestmclarenfan Java 2 02-16-2006 08:05 PM
Client socket disconnection event not received on Server socket java .nio Avizz Java 3 09-29-2003 10:47 AM



Advertisments