1

我从这里有这段代码:

#!/usr/bin/python

from asyncore import dispatcher
from asynchat import async_chat
import socket, asyncore

PORT = 55555
NAME = 'ChatLine'

class ChatSession(async_chat):
    def __init__(self,server,sock):
        async_chat.__init__(self, sock)
        self.server = server
        self.set_terminator("\r\n")
        self.data = []

    def collect_incoming_data(self, data):
        self.data.append(data)

    def found_terminator(self):
        line = "".join(self.data)
        self.data = []
        self.server.broadcast(line)

    def handle_close(self):
        async_chat.handle_close(self)
        self.server.disconnect(self)

class ChatServer(dispatcher):
    def __init__(self, port, name):
        dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.set_reuse_addr()
        self.bind(("",port))
        self.listen(5)
        self.name = name
        self.sessions = []

    def disconnect(self, sessions):
        self.sessions.remove(session)

    def broadcast(self, line):
        for session in self.sessions:
            session.push('>>' + line + '\r\n')

    def handle_accept(self):
        conn, addr = self.accept()
        print "Connected from " + str(addr)
        self.sessions.append(ChatSession(self, conn))

if __name__ == '__main__':
    s = ChatServer(PORT, NAME)
    try: asyncore.loop()
    except KeyboardInterrupt: print

如果我使用 putty/telnet 或任何其他软件连接它,我将得到以下输出:

test
>>test

首先test是我发送的内容,其次>>>test是服务器广播回来的内容。

我怎样才能删除我发送的同一条消息的广播,所以我不会得到第二个>>>test?也许我可以注册会话 ID 或任何其他数据,当服务器广播消息时,我可以将数据发送到除先前记录的会话之外的所有会话?

或者也许我可以添加用户名并使用它来删除重复的消息?

我没有找到任何关于 asyncore 或 asychat 的教程或文档,因此我们将不胜感激。

4

1 回答 1

2

Your sessions list on ChatServer contains all of the ChatSession instances representing connections to your server.

This includes the ChatSession that sent a particular message to the server. If you want to send that message out to all of the other connections, then you just need to skip one of the ChatSession instances in the loop inside broadcast. To know which one to skip, you might add an argument to broadcast:

def broadcast(self, line, skip):

And then use it to not call push one time through the loop:

    for session in self.sessions:
        if session is skip:
            session.push('Alternate pedagogical output\r\n')
        else:
            session.push('>>' + line + '\r\n')

Here I haven't actually skipped the session, just gave it different treatment so you can easily tell that something different is happening to it (instead of seeing no output, which could also be caused by some other bug...)

Now you just need to change the caller to pass this argument. Fortunately, the caller is a method of ChatSession where the correct ChatSession to skip is easily available - as self!

So just change the found_terminate method of ChatSession to look like...

def found_terminator(self):
    line = "".join(self.data)
    self.data = []
    self.server.broadcast(line, skip=self)

As you can see, this isn't really taking advantage of any asyncore or asynchat features. It's just some more logic in your application code.

Incidentally, Twisted is a lot more featureful than asynchat - so I recommend you spend your time learning that, instead. For a taste, here's your chat server written with Twisted:

from twisted.internet import reactor
from twisted.internet.protocol import Factory
from twisted.protocols.basic import LineOnlyReceiver

PORT = 55555

class ChatSession(LineOnlyReceiver):
    def connectionMade(self):
        print "Connection from", self.transport.getPeer()
        self.factory.sessions.append(self)

    def connectionLost(self, reason):
        self.factory.sessions.remove(self)

    def lineReceived(self, line):
        self.factory.broadcast(line, skip=self)

    def send(self, line):
        self.sendLine('>>' + line)

class ChatServer(Factory):
    protocol = ChatSession

    def __init__(self):
        self.sessions = []

    def broadcast(self, line, skip):
        for session in self.sessions:
            if session is not skip:
                session.send(line)

reactor.listenTCP(PORT, ChatServer())
reactor.run()
于 2013-04-18T17:34:46.990 回答