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和php通信乱码问题解决方法
Apr 15 Python
python中lambda函数 list comprehension 和 zip函数使用指南
Sep 28 Python
Python+Django搭建自己的blog网站
Mar 13 Python
python机器学习之贝叶斯分类
Mar 26 Python
Python登录注册验证功能实现
Jun 18 Python
python使用scrapy发送post请求的坑
Sep 04 Python
在Python中过滤Windows文件名中的非法字符方法
Jun 10 Python
关于Python中的向量相加和numpy中的向量相加效率对比
Aug 26 Python
python 实现按对象传值
Dec 26 Python
打印tensorflow恢复模型中所有变量与操作节点方式
May 26 Python
Python描述数据结构学习之哈夫曼树篇
Sep 07 Python
学会Python数据可视化必须尝试这7个库
Jun 16 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
怎样在UNIX系统下安装MySQL
2006/10/09 PHP
PHP explode()函数用法、切分字符串
2012/10/03 PHP
PHP数组操作简单案例分析
2016/10/15 PHP
如何用javascript判断录入的日期是否合法
2007/01/08 Javascript
解决IE下select标签innerHTML插入option的BUG(兼容IE,FF,Opera,Chrome,Safari)
2010/05/13 Javascript
JavaScript随机排序(随即出牌)
2010/09/17 Javascript
eval的两组性能测试数据
2012/08/17 Javascript
jQuery 的全选(全非选)即取得被选中的值使用介绍
2013/11/12 Javascript
使用jQuery解决IE与FireFox下createElement方法的差异
2013/11/14 Javascript
屏蔽IE弹出"您查看的网页正在试图关闭窗口,是否关闭此窗口"的方法
2013/12/31 Javascript
判断一个对象是否为jquery对象的方法
2014/03/12 Javascript
jQuery插件ImageDrawer.js实现动态绘制图片动画(附源码下载)
2016/02/25 Javascript
JS面向对象编程详解
2016/03/06 Javascript
js插件实现图片滑动验证码
2020/09/29 Javascript
JavaScript惰性载入函数实例分析
2019/03/27 Javascript
vue单页面在微信下只能分享落地页的解决方案
2019/04/15 Javascript
ES6顶层对象、global对象实例分析
2019/06/14 Javascript
JavaScript设计模式--简单工厂模式定义与应用案例详解
2020/05/23 Javascript
[39:08]完美世界DOTA2联赛PWL S3 LBZS vs CPG 第一场 12.12
2020/12/16 DOTA
深入理解Javascript中的this关键字
2015/03/27 Python
利用PyInstaller将python程序.py转为.exe的方法详解
2017/05/03 Python
python虚拟环境的安装配置图文教程
2017/10/20 Python
python的格式化输出(format,%)实例详解
2018/06/01 Python
基于Python3.6+splinter实现自动抢火车票
2018/09/25 Python
快速解决vue.js 模板和jinja 模板冲突的问题
2019/07/26 Python
tensorflow 报错unitialized value的解决方法
2020/02/06 Python
找Python安装目录,设置环境路径以及在命令行运行python脚本实例
2020/03/09 Python
Numpy中ndim、shape、dtype、astype的用法详解
2020/06/14 Python
Pytorch 解决自定义子Module .cuda() tensor失败的问题
2020/06/23 Python
理解Django 中Call Stack机制的小Demo
2020/09/01 Python
naturalizer加拿大官网:美国娜然女鞋
2017/04/04 全球购物
培训主管的职业生涯规划
2014/03/06 职场文书
学术会议主持词
2014/03/17 职场文书
医生个人自我剖析材料
2014/10/08 职场文书
大学生学期个人总结
2015/02/12 职场文书
2019年恭贺升学祝福语集锦
2019/08/15 职场文书