Python練習2-基本聊天程式-虛擬茶會話__Python

來源:互聯網
上載者:User
基本聊天程式

先來個基本的測試例子:

Main.py

from asyncore import dispatcherimport socket,asyncorePORT = 11223class ChatServer(dispatcher):    def __init__(self, port):        dispatcher.__init__(self)        self.create_socket(socket.AF_INET ,socket.SOCK_STREAM)        self.set_reuse_addr()        self.bind(('',port))        self.listen(5)    def handle_accept(self):        conn,addr = self.accept()        print ('Connection attempt from',addr[0]) if __name__ == '__main__':    s = ChatServer(PORT)    try:asyncore.loop()except KeyboardInterrupt:pass


    上面是伺服器段程式,接受到串連之後馬上在伺服器上顯示對方IP,但是不保持串連。用戶端測試的話很簡單,可以自己寫一個socket的串連,也可以為了省事直接本地開啟telnet就行了,開啟telnet的方法是,在開始菜單裡搜尋:



然後確定,之後cmd裡直接telnet就行了。



運行上面的main.py,然後用戶端連結服務端:

Cmd->telnet    : open 127.0.0.1 11223


    上面就是一個最基本的Python伺服器指令碼流程。接下來實現一個基本的聊天程式用來練手。

     實現的準系統(虛擬茶會話) 測試環境python 3.6.0[python基礎教程上的代碼不能直接在3.6.0版本上跑,以下是改過的虛擬茶會話]

功能:

login name 登入房間

logout 退出房間

say   XXXX 發言

look 查看同一個房間內的人

who 查看誰登陸了當前伺服器

測試截圖


 

簡單說下設計結構:

CommandHandler類 : 處理命令的,函數存在則執行,不存在則直接走unknown函數。結合著try和getattr函數python可以直接嘗試去執行一個不確定存不存在的函數。[我一直在想,別的語言要怎麼實現這個東西,是建立虛擬工廠。對了想起來了,乾脆就建立一些函數,然後把函數名字格式化封裝在一個void指標容器裡的了。函數格式化要統一]


Room類:表示一個房間,裡面有一些對房間人[連結]資料結構的增加刪除操作,同時還有相關廣播函數,用於把訊息發給所有人。


LoginRoom類,裡面有成功登陸房間,登陸房間失敗以及登陸操作,比如問候登陸者,同時通知別人有人登陸等細節。


LogoutRoom類,登出房間類,使用者登出房間時候進行的一些資料結構處理。


ChatRoom類,聊天室類,主要就是封裝了一些功能函數。比如say look who等等。


ChatSession,ChatServer 類基本的伺服器程式需要的,分別繼承async_chat和dispatcher,處理一些伺服器參數,以及重載設定一些處理函數等。

 

詳細代碼如下[注意本代碼測試於python3.6.0]

#!/usr/bin/env python3__author__ = 'tcstory'from asyncore import dispatcherfrom asynchat import async_chatimport socket, asyncore PORT=5005NAME='TestChat' class EndSession(Exception): pass class CommandHandler:    '''    Simple command handler similar to cmd.Cmd from the standard library    '''     def unknown(self, session, cmd):        'Respond to an unknown command'        session.push('Unkonw command: {0}\r\n'.format(cmd).encode())     def handle(self, session, line):        'Handle a received line from a given session'        if not line.strip():            return        #Split off the command        parts = line.split(' ', 1)        cmd = parts[0]        try:            line=parts[1].strip()        except IndexError:            line=''        #Try to find a handler        meth=getattr(self,'do_'+cmd,None)        try:            #Assume it's callable            meth(session,line)        except TypeError:            #If it isn't ,respond to the unknown command            self.unknown(session,cmd) class Room(CommandHandler):    '''    A generic environment that may contain one or more users(sessions).it takes care of basic command handling and broadcasting.    '''    def __init__(self,server):        self.server=server        self.sessions=[]     def add(self,session):        'A session(user) has entered the room'        self.sessions.append(session)     def remove(self,session):        'A session (user) has left the room'        self.sessions.remove(session)     def broadcast(self,line):        'Send a line to all sessions in the room'        for session in self.sessions:            session.push(line.encode())     def do_logout(self,session,line):        'Respond to the logout command'        raise EndSession class LoginRoom(Room):    '''    A room meant for a single person who has just connected    '''     def add(self,session):        Room.add(self,session)        #When a user enters,greet him/her        self.broadcast('Welcome to {0}\r\n'.format(self.server.name))     def unknown(self, session, cmd):        #All unknown commands (anything except login or logout)        #results in a prodding        session.push('Please log in\nUse "login <nick>"\r\n'.encode())     def do_login(self,session,line):        name=line.strip()        #Make sure the user has entered a name        if not name:            session.push('Please enter a name\r\n'.encode())        #Make sure that the name isn't in use        elif name in self.server.users:            session.push('The name {0} is taken.\r\n'.format(name).encode())            session.push('Please try again.\r\n'.encode())        else:            #The name is OK,os it is stored in the session.and            #the user is moved into the main room            session.name=name            session.enter(self.server.main_room) class ChatRoom(Room):    '''    A room meant for multiple users who can chat with the others in the room    '''     def add(self,session):        #Notify everyone that a new user has entered        self.broadcast('{0} has entered the room.\r\n'.format(session.name))        self.server.users[session.name]=session        Room.add(self,session)     def remove(self,session):        Room.remove(self,session)        #Notify everyone that a user has left        self.broadcast('{0} has left the room.\r\n'.format(session.name))     def do_say(self,session,line):        self.broadcast(('{0}: '+line+'\r\n').format(session.name))     def do_look(self,session,line):        'Handles the look command,used to see who is in a room'        session.push('The following are in this room:\r\n'.encode())        for other in self.sessions:            session.push('{0}\r\n'.format(other.name).encode())     def do_who(self,session,line):        'Handles the who command ,used to see who is logged in'        session.push('The following are logged in:\r\n'.encode())        for name in self.server.users:            session.push('{0}\r\n'.format(name).encode()) class LogoutRoom(Room):    '''    A simple room for a single user.Its sole purpose is to remove the user's name from the server    '''     def add(self,session):        #When a session (user) enters the LogoutRoom it is deleted         try:            del self.server.users[session.name]        except KeyError:            pass class ChatSession(async_chat):    '''    A single session,which takes care of the communication with a single user    '''     def __init__(self,server,sock):        # async_chat.__init__(self,sock)        super().__init__(sock)        self.server=server        self.set_terminator(b'\r\n')        self.data=[]        self.name=None        #All sessions begin in a separate LoginRoom        self.enter(LoginRoom(server))     def enter(self,room):        # Remove self from current room and add self to next room....        try:            cur=self.room        except AttributeError:pass        else:            cur.remove(self)        self.room=room        room.add(self)     def collect_incoming_data(self, data):         self.data.append(data.decode('utf-8'))     def found_terminator(self):        line=''.join(self.data)        self.data=[]        try:            self.room.handle(self,line)        except EndSession:            self.handle_close()     def handle_close(self):        async_chat.handle_close(self)        self.enter(LogoutRoom(self.server)) class ChatServer(dispatcher):    '''    A chat server with a single room    '''     def __init__(self,port,name):        super().__init__()        # 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.users={}        self.main_room=ChatRoom(self)     def handle_accept(self):        conn,addr=self.accept()        ChatSession(self,conn) if __name__=='__main__':    s=ChatServer(PORT,NAME)    try:        asyncore.loop()    except KeyboardInterrupt:        print()


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.