There are two files: server.py and client.py, both written with the help of asyncore.dispatcher
Server.py
import asyncore, socket
class Server(asyncore.dispatcher):
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.bind(('', port))
self.listen(1)
print "Waiting for connection..."
def handle_accept(self):
socket, address = self.accept()
print 'Connection by', address
socket.send("Hello Server")
def handle_read(self):
print "Reading..."
out_buffer = self.recv(1024)
if not out_buffer:
self.close()
print out_buffer
def handle_closed(self):
print "Server: Connection Closed"
self.close()
s = Server('0.0.0.0', 5007)
asyncore.loop()
Client.py
import asyncore, socket
class Client(asyncore.dispatcher):
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.connect((host, port))
print "Client Start..."
def handle_close(self):
print "Client: Connection Closed"
self.close()
def handle_read(self):
data = self.recv(1024)
if data:
print "Received ", data
self.send("Hello Client")
c = Client('127.0.0.1', 5007)
asyncore.loop()
Result:
Execute server.py
:
Waiting for connection...
then client.py
:
Client Start...
Received Hello Server
Client: Connection Closed
Client: Connection Closed
Finally the client.py exited, and there is one more line displayed in the ouput window of server.py and the server keeps running:
Connection by ('127.0.0.1', 58197)
There are something that I cannot understand:
Why is the function handle_closed
in client.py executed twice?
Why isn't the function handle_reading
in server.py executed? The client.py has sent message("Hello Client"), but why cannot the server receive it?
Why isn't the function handle_closed
in server.py executed? I want to execute some codes in server.py when the client exits, but it seems that it does nothing to do handle_closed
in server.py?
The handle_read()
in server.py will never be called.
But why?! It's a server class...
Yes, but Server
class uses its socket for listening any non-established connections. Any reads on it go to handle_accept()
, where actual channel sockets (connected to some endpoint) should be given to new instance of some dispatcher
-inherited class (preferably). In your Server
's handle_accept()
method sockets got by accept()
were local and thus deleted upon exiting this function, so: new connection was accepted, text was sent and after that socket was immediately killed.
Have some read on asyncore module and my answer in other question.
You need to, like I said, make new class for connections in server.py:
class ClientHandler(asyncore.dispatcher):
def handle_read(self):
data = self.recv(1024)
if not data:
return
print "Received:", data
def handle_close(self):
print "Server: Connection Closed"
self.close()
Note here that reading don't need to manually close socket when null is recieved - asyncore
takes care of properly closing connection.
Then you have to instantiate it in Server
when connection is made:
def handle_accept(self):
...
ClientHandler(socket)
You also made spelling mistake in Server
- method's proper name is handle_close
. Though it wouldn't be useful. Everything client-connection related is in ClientHandler
.
In client.py you just need to modify handle_read()
:
if data:
print "Received ", data
Change to:
if not data:
return
print "Received ", data
Why? Without this send()
would be called even when socket is actually closed, resulting in handle_close()
being called for second time, by asyncore
. Like I said - asyncore
takes care of this.
Now you can write more complex server-side class for connections. You could also learn how OS-level sockets work, so you won't get into trouble.
asyncore
itself is a pretty nice wrapper for sockets, but if you want to do higher-lever things, like HTTP or SMTP processing in some event-driven environment, then Twisted library would interest you!