2013-04-18 47 views
1

我從here驗證碼:與asynchat獲取會話數據的Python聊天

#!/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 

如果我用膩子/ Telnet或任何其他軟件把它連接我得到這樣的輸出:

test 
>>test 

第一個test是我發送的,第二個>>>test是服務器回放的內容。

我如何刪除我發送相同的消息的廣播,所以我不會得到第二>>>test?也許我可以註冊會話ID或任何其他數據,當服務器廣播消息時,我可以將數據發送到除先前記錄的會話之外的所有會話?

或者我可以添加用戶名並使用它來刪除重複的消息?

我沒有找到有關asyncore或asychat任何教程或文檔,因此任何幫助,將不勝感激。

回答

2

sessions名單上ChatServer包含了所有代表連接到您服務器的ChatSession實例。

這包括髮送的特定消息發送到服務器的ChatSession。如果要將該消息發送給所有其他連接,則只需跳過broadcast內循環中的ChatSession實例之一。要知道跳到哪一個,您可以添加一個參數廣播:

def broadcast(self, line, skip): 

然後用它來通話push一次通過循環:

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

在這裏我沒有實際上跳過了會議,只是給它不同的處理,使您可以輕鬆地告訴大家,一些不同的是發生在它(而不是看到沒有輸出,也可以通過一些其它的錯誤引起的...)

現在你只需要更改調用者來傳遞這個參數。幸運的是,來電者是一種方法ChatSession,其中正確的ChatSession跳過很容易獲得 - 作爲self

因此,只要改變ChatSessionfound_terminate方法看起來像......

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

正如你可以看到,這是不是真的服用任何asyncore或asynchat功能。這只是應用程序代碼中的更多邏輯。

順便說一句,Twisted是一個很多比asynchat更多的其他功能 - 所以我建議你花時間學習的是,來代替。一個人的滋味,這裏是與扭曲的編寫你的聊天服務器:

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()