zoukankan      html  css  js  c++  java
  • Python练习2-基本聊天程序-虚拟茶会话

    基本聊天程序

    先来个基本的测试例子:

    Main.py

    from asyncore import dispatcher
    import socket,asyncore
    PORT = 11223
    class 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等等。


    ChatSessionChatServer 类基本的服务器程序需要的,分别继承async_chatdispatcher,处理一些服务器参数,以及重载设置一些处理函数等。

     

    详细代码如下[注意本代码测试于python3.6.0]

    #!/usr/bin/env python3
    __author__ = 'tcstory'
    from asyncore import dispatcher
    from asynchat import async_chat
    import socket, asyncore
     
    PORT=5005
    NAME='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}
    '.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}
    '.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
    Use "login <nick>"
    '.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
    '.encode())
            #Make sure that the name isn't in use
            elif name in self.server.users:
                session.push('The name {0} is taken.
    '.format(name).encode())
                session.push('Please try again.
    '.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.
    '.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.
    '.format(session.name))
     
        def do_say(self,session,line):
            self.broadcast(('{0}: '+line+'
    ').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:
    '.encode())
            for other in self.sessions:
                session.push('{0}
    '.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:
    '.encode())
            for name in self.server.users:
                session.push('{0}
    '.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'
    ')
            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()


  • 相关阅读:
    windows2012 永激活及配置
    Fiddler2 英文版翻译
    你知道using的用法吗?
    你会利用css写下拉列表框吗?
    完美解决.net2.0和.net4.0在同一个iis中共同运行
    深入剖析new override和virtual关键字
    思科防火墙,h3c三层交换机配置笔记
    c# 笔记 数据类型转换 数组 函数
    Silverlight 完美征程 笔记1 (控件模型)
    C#笔记(流程控制)
  • 原文地址:https://www.cnblogs.com/csnd/p/12061963.html
Copyright © 2011-2022 走看看