python基础教程项目五之虚拟茶话会


Posted in Python onApril 02, 2018

几乎在学习、使用任何一种编程语言的时候,关于socket的练习从来都不会少,尤其是会写一些局域网的通信的东西。所以书上的这个项目刚好可以练习一下socket编程。

这个练习的整体思路首先有一个聊天的服务器,这个服务器的功能主要是提供客户端socket的连接、存储每个客户端的连接session,处理每个连接发送的消息、解析客户端发送的数据。就这些,至于客户端方面不需要写代码,用系统的telnet工具即可。

我觉得有了上面的分析,剩下的这个程序就没有什么说的了,当然,除了那两个把socket封装的类之外。

自己使用python中的socket类尝试这个编写了一个简单的通信程序,不过不知为什么,通信中总是出现意外。这段简单的代码如下:

server.py

import socket

mysocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
mysocket.bind(('',8888))
mysocket.listen(5)

while True:
    connection,addr = mysocket.accept()
    revStr = connection.recv(1024)
    connection.send('Server:' + revStr)
    connection.close()

clinet.py

import socket
import time

clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

clientsocket.connect(('',8888))
while True:
    time.sleep(2)
    clientsocket.send('hello the5fire')
    print clientsocket.recv(1024)

clientsocket.close()

这个程序出错的原因没有去细揪,因为python中提供了两个封装好的类来完成socket通信过程:asynchat中的async_chat和asyncore中的dispatcher以及asyncore本身。前面的类是用来处理客户端同服务器的每一次会话,后面的类主要是用来提供socket连接服务。并且将每一个socket连接都托管给前者(async_chat)来处理。

来看代码:

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

PORT = 5005
NAME = 'TestChat'

class EndSession(Exception):pass

class CommandHandler:

    def unknown(self, session, cmd):
        session.push('Unknown command: %s\r\n' % cmd)

    def handle(self, session, line):
        if not line.strip(): return

        parts = line.split(' ',1)
        cmd = parts[0]
        try: line = parts[1].strip()
        except IndexError: line = ''

        meth = getattr(self, 'do_'+cmd, None)

        try:
            meth(session, line)
        except TypeError:
            self.unknown(session,cmd)

class Room(CommandHandler):

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

    def add(self, session):
        self.sessions.append(session)

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

    def broadcast(self, line):
        for session in self.sessions:
            session.push(line)

    def do_logout(self, session, line):
        raise EndSession

class LoginRoom(Room):

    def add(self,session):
        Room.add(self,session)

        self.broadcast('Welcome to %s\r\n' % self.server.name)

    def unknown(self, session, cmd):
        session.push('Please log in \nUse "login"\r\n')

    def do_login(self, session, line):
        name = line.strip()

        if not name:
            session.push('Please enter a name\r\n')
        elif name in self.server.users:
            session.push('The name "%s" is taken.\r\n' % name)
            sessoin.push('Please try again.\r\n')
        else:
            session.name = name
            session.enter(self.server.main_room)

class ChatRoom(Room):

    def add(self, session):
        self.broadcast(session.name + ' has entered the room.\r\n')
        self.server.users[session.name] = session
        Room.add(self, session)

    def remove(self, session):
        Room.remove(self, session)

        self.broadcast(session.name + ' has left the room.\r\n')

    def do_say(self, session, line):
        self.broadcast(session.name + ': ' + line + '\r\n')

    def do_look(self, session, line):
        session.push('The following are in this room:\r\n')
        for other in self.sessions:
            session.push(other.name + '\r\n')

    def do_who(self, session, line):
        session.push('The following are logged in:\r\n')
        for name in self.server.users:
            session.push(name + '\r\n')

class LogoutRoom(Room):

    def add(self, session):
        try: del self.server.users[session.name]
        except KeyError: pass

class ChatSession(async_chat):

    def __init__(self, server, sock):
        async_chat.__init__(self,sock)
        self.server = server
        self.set_terminator('\r\n')
        self.data = []
        self.name = None

        self.enter(LoginRoom(server))

    def enter(self, 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)

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

    def __init__(self, port, name):
        dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        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

整个程序分为我一开始说的三个部分:

提供客户端的socket连接:ChatServer类。

存储每个客户端的连接session,处理每个连接发送的消息:ChatSession类,这个类的作用很简单,接受数据,判断是否有终结符,如果有调用found_terminator这个方法。

解析客户端发送的数据:就是剩下的room相关的类,这些类分别用来处理客户端发送的字符串和命令,都是继承自CommandHandler。

最终截图:

python基础教程项目五之虚拟茶话会

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python验证企业工商注册码
Oct 25 Python
Python 加密的实例详解
Oct 09 Python
简单实现python画圆功能
Jan 25 Python
Windows下的Jupyter Notebook 安装与自定义启动(图文详解)
Feb 21 Python
Python 新建文件夹与复制文件夹内所有内容的方法
Oct 27 Python
python增加图像对比度的方法
Jul 12 Python
python中resample函数实现重采样和降采样代码
Feb 25 Python
Django Admin后台添加数据库视图过程解析
Apr 01 Python
3分钟看懂Python后端必须知道的Django的信号机制
Jul 26 Python
Python猫眼电影最近上映的电影票房信息
Sep 18 Python
虚拟环境及venv和virtualenv的区别说明
Feb 05 Python
梳理总结Python开发中需要摒弃的18个坏习惯
Jan 22 Python
Python实现批量读取图片并存入mongodb数据库的方法示例
Apr 02 #Python
python基础教程项目四之新闻聚合
Apr 02 #Python
Python实现将数据框数据写入mongodb及mysql数据库的方法
Apr 02 #Python
python基础教程项目三之万能的XML
Apr 02 #Python
python opencv检测目标颜色的实例讲解
Apr 02 #Python
浅谈python配置与使用OpenCV踩的一些坑
Apr 02 #Python
python基础教程项目二之画幅好画
Apr 02 #Python
You might like
收音机史话 - 1960年代前后的DIY
2021/03/02 无线电
php下关于Cannot use a scalar value as an array的解决办法
2010/08/08 PHP
PHP实现实时生成并下载超大数据量的EXCEL文件详解
2017/10/23 PHP
PHP实现的简单组词算法示例
2018/04/10 PHP
PHP时间处理类操作示例
2018/09/05 PHP
javascript中length属性的探索
2011/07/31 Javascript
在NodeJS中启用ECMAScript 6小结(windos以及Linux)
2014/07/15 NodeJs
详谈nodejs异步编程
2014/12/04 NodeJs
EasyUI中实现form表单提交的示例分享
2015/03/01 Javascript
js中this用法实例详解
2015/05/05 Javascript
javascript获取wx.config内部字段解决微信分享
2016/03/09 Javascript
js实现div在页面拖动效果
2016/05/04 Javascript
JS实现table表格数据排序功能(可支持动态数据+分页效果)
2016/05/26 Javascript
对Angular.js Controller如何进行单元测试
2016/10/25 Javascript
Vue学习笔记进阶篇之多元素及多组件过渡
2017/07/19 Javascript
vue项目打包部署_nginx代理访问方法详解
2018/09/20 Javascript
详解关于element el-button使用$attrs的一个注意要点
2018/11/09 Javascript
Vue源码探究之状态初始化
2018/11/14 Javascript
Vue2.0 $set()的正确使用详解
2020/07/28 Javascript
Vue将props值实时传递 并可修改的操作
2020/08/09 Javascript
vue中jsonp插件的使用方法示例
2020/09/10 Javascript
在Python中操作字典之setdefault()方法的使用
2015/05/21 Python
python 简单备份文件脚本v1.0的实例
2017/11/06 Python
python 判断网络连通的实现方法
2018/04/22 Python
Python基础学习之函数方法实例详解
2019/06/18 Python
如何使用pycharm连接Databricks的步骤详解
2020/09/23 Python
屈臣氏官方旗舰店:亚洲享负盛名的保健及美妆零售商
2019/03/15 全球购物
旷课检讨书1000字
2014/02/14 职场文书
小学校本培训方案
2014/06/06 职场文书
2014年医德医风工作总结
2014/11/13 职场文书
考试作弊检讨书
2015/01/27 职场文书
巴黎圣母院读书笔记
2015/06/26 职场文书
党员观看《筑梦中国》心得体会
2016/01/18 职场文书
九年级数学教学反思
2016/02/17 职场文书
教你用Python写一个植物大战僵尸小游戏
2021/04/25 Python
Python OpenCV超详细讲解基本功能
2022/04/02 Python