0

I have an IP = '127.0.0.1', port number 'port', and trying

class AClass(asyncore.dispatcher):
     def __init__(self, ip, port):        
        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)        
        self.connect((ip, port))

    def handle_connect(self):
        print 'connected'   

    def handle_read(self):        
        data = self.recv(8192)
        print data   

    def handle_close(self):
        self.close()

Nothing is being printed though.

The sending is being handled by another process. How can I check ? Is the above correct ?

Edit: For sending: a different python program, running separately:

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((addr, port))
packet="some string"
sock.sendall(packet+'\r\n') 

Nothing happens

If I put, on server side (!!!) print sock.recv(4096) I see the packet printed - but still nothing happens from the client side.

Thalia
  • 13,637
  • 22
  • 96
  • 190

1 Answers1

2

I assume that you mean for AClass to be the server-side. In that case, AClass should not be doing a connect(). There are two sides to socket communications. On the server-side, you typically create the socket, bind it to an address and port, set the backlog (via listen()), and accept() connections. Typically, when you have a new connection from a client, you spawn off some other entity to handle that client.

This code implements an echo server:

import asyncore
import socket


class EchoHandler(asyncore.dispatcher_with_send):
    def handle_read(self):
        self.out_buffer = self.recv(1024)
        if not self.out_buffer:
            self.close()
        print "server:", repr(self.out_buffer)

    def handle_close(self):
        self.close()


class EchoServer(asyncore.dispatcher):
    def __init__(self, ip, port):
        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.set_reuse_addr()
        self.bind((ip, port))
        self.listen(1)

    def handle_accept(self):
        sock, addr = self.accept()

        print "Connection from", addr

        EchoHandler(sock)

s = EchoServer('127.0.0.1', 21345)
asyncore.loop()

Notice that in the __init__() method, I'm binding the socket, and setting the backlog. handle_accept() is what handles the new incoming connection. In this case, we get the new socket object and address returned from accept(), and create a new async handler for that connection (we supply the socket to EchoHandler). EchoHandler then does the work of reading from the socket, and then puts that data into out_buffer. asyncore.dispatcher_with_send will then notice that data is ready to send and write it to the socket behind the scenes for us, which sends it back to the client. So there we have both sides, we've read data from the client, and then turn around and send the same data back to the server.

You can check this implementation in a couple of ways. Here is some python code to open a connection, send a message, read the response, and exit:

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((ip, port))
client.sendall("Hello world!\r\n")
print "client:", repr(client.recv(1024))
client.close()

You can also just use telnet as your client using the command telnet localhost 21345, for this example. Type in a string, hit enter, and the server will send that string back. Here's an example session I did:

:: telnet 127.0.0.1 21345
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello!
Hello!
aouaoeu aoeu aoeu
aouaoeu aoeu aoeu
^]
telnet> quit
Connection closed.

In the example, the first "Hello!" is the one I typed in my client, the second one is the echo from the server. Then I tried another string, and it was echoed back as well.

If you've not done socket communications before, I really can't recommend Richard Stevens UNIX Network Programming enough. A 3rd edition is now in print and available on Amazon. It doesn't, however, cover using Python or asyncore. And, unfortunately, asyncore is one module that's really not covered very well in the Python documentation. There some examples out there in the wild that are pretty decent though.

Hopefully, this gets you moving in the right direction.

EDIT: here's a asyncore based client:

class Client(asyncore.dispatcher_with_send):
    def __init__(self, ip, port, message):
        asyncore.dispatcher_with_send.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connect((ip, port))
        self.out_buffer = message

    def handle_connect(self):
        print 'connected'

    def handle_read(self):
        data = self.recv(8192)
        print "client:", repr(data)

    def handle_close(self):
        self.close()
John Szakmeister
  • 44,691
  • 9
  • 89
  • 79
  • Thank you, this is helpful, I am trying to find from your response, something that could help me. There is a "server", already implemented, that has a broadcast method, I copied it to create a unicast that I am fairly sure works. What I am trying to make is a CLIENT, not a server, something that connects to the server and gets the message. Is my interpretation correct ? Still, the best that I could get (with the code I have, above) was an error "An existing connection was forcibly closed by the remote host". As for the server - it has classes similar to your answer. – Thalia Oct 10 '12 at 16:26
  • I added a client implementation. I had done it this morning, but thought--based on your question--that you were aiming for something else. – John Szakmeister Oct 10 '12 at 23:31
  • Thank you. In the constructor though, in the client, what is the "message" ? Where would the client get it ? – Thalia Oct 10 '12 at 23:37
  • I just wrote it - minus the "message", but I still get nothing printed from client... – Thalia Oct 10 '12 at 23:41
  • `message` is the message to pass to the echo server on the other end. The server will the spin it around and send it back. I don't know how your server operates... does it expect the client to initiate communication somehow? How are you doing that? Does the server just send something? I somehow doubt it, or you'd see that. You need to understand the protocol that server is speaking, and adhere to that in your client. So, if it expects you to speak first, you need to speak. The `Client` class does this above using the `message` parameter. Your client may need to do something different. – John Szakmeister Oct 10 '12 at 23:46
  • BTW, if you use the client I wrote against the echo server earlier in my response, you'll see it answer. – John Szakmeister Oct 10 '12 at 23:49
  • The server: opens a socket, starts a new python program (the client) as subprocess and sends it the ip and port, then will communicate required messages as needed. I have asked this question, again, as I was trying to figure out how to make them communicate using multicasting, here: http://stackoverflow.com/questions/12829164/python-multicast-failure-to-communicate?lq=1 - and added more of the server code. – Thalia Oct 10 '12 at 23:55
  • There is no `listen()`, and no `accept()` in your server code of the referenced question. It's hard to see how that code could possibly work. :-( – John Szakmeister Oct 11 '12 at 00:42
  • Even though I experimented with the above code, and many other options, including broadcasting, I have been unable to solve this issue, and still have no idea how I can debug it. It may be that one other class using asyncore.dispatcher is holding onto a port (though I thought set_reuse_addr() should fix that issue - it may not allow port reuse ?). I have learnt a bit about asyncore.dispatcher, but not enough. Most examples on the web are the same echo (is this like hello world ?)... I suppose I'll accept this answer, and experiment some more. – Thalia Oct 15 '12 at 23:57
  • To be honest, I still don't know exactly what you're asking with your question. I attempted to show you that having sockets talk with asyncore is definitely possible. But you seem to want to do something else, and it's unclear to me what you're looking for. – John Szakmeister Oct 17 '12 at 08:12