Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Socket : 2 way communication in python

Tags:

python

sockets

I want a two way communication in Python :

I want to bind to a socket where one client can connect to, and then server and client can "chat" with eachother.

I already have the basic listener :

import socket
HOST='' #localhost
PORT=50008

s=socket.socket(socket.AF_INET, socket.SOCK_STREAM ) #create an INET, STREAMing socket
s.bind((HOST,PORT)) #bind to that port
s.listen(1) #listen for user input and accept 1 connection at a time.

conn, addr = s.accept()

print "The connection has been set up"
bool=1
while bool==1:
        data=conn.recv(1024)
        print data
        if "#!END!#" in data:
                print "closing the connection"
                s.close()
                bool=0

What I want to do now is implement something so this script also accepts user input and after the enter key is hit, send it back to the client.

But I can't figure out how I can do this ? Because if I would do it like this :

while bool==1:
    data=conn.recv(1024)
    print data
    u_input = raw_input("input now")
    if u_input != "":
       conn.send(u_input)
       u_input= ""

Problem is that it probably hangs at the user input prompt, so it does not allow my client to send data.

How do I solve this ?

I want to keep it in one window, can this be solved with threads ?

(I've never used threads in python)

like image 774
Lucas Kauffman Avatar asked Nov 23 '11 20:11

Lucas Kauffman


2 Answers

Python's sockets have a makefile tool to make this sort of interaction much easier. After creating a socket s, then run f = s.makefile(). That will return an object with a file-like interface (so you can use readline, write, writelines and other convenient method calls). The Python standard library itself makes use of this approach (see the source for ftplib and poplib for example).

To get text from the client and display it on the server console, write a loop with print f.readline().

To get text from the server console and send it to the client, write a loop with f.write(raw_input('+ ') + '\n').

To be send and receive at the same time, do those two steps separate threads:

 Thread(target=read_client_and_print_to_console).start()
 Thread(target=read_server_console_and_send).start()

If you prefer async over threads, here are two examples to get you started:

  • Basic Async HTTP Client
  • Basic Async Echo Server
like image 173
Raymond Hettinger Avatar answered Oct 20 '22 01:10

Raymond Hettinger


The basic problem is that you have two sources of input you're waiting for: the socket and the user. The three main approaches I can think of are to use asynchronous I/O, to use synchronous (blocking) I/O with multiple threads, or to use synchronous I/O with timeouts. The last approach is conceptually the simplest: wait for data on the socket for up to some timeout period, then switch to waiting for the user to enter data to send, then back to the socket, etc.

I know at a lower level, you could implement this relatively easily by treating both the socket and stdin as I/O handles and use select to wait on both of them simultaneously, but I can't recall if that functionality is mapped into Python, or if so, how. That's potentially a very good way of handling this if you can make it work. EDIT: I looked it up, and Python does have a select module, but it sounds like it only functions like this under Unix operating systems--in Windows, it can only accept sockets, not stdin or files.

like image 36
qid Avatar answered Oct 20 '22 02:10

qid