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结合shell查询google关键词排名的实现代码
Feb 27 Python
Python多线程经典问题之乘客做公交车算法实例
Mar 22 Python
Python 基础教程之闭包的使用方法
Sep 29 Python
Python打印“菱形”星号代码方法
Feb 05 Python
python实现音乐下载器
Apr 15 Python
Python3爬虫学习之将爬取的信息保存到本地的方法详解
Dec 12 Python
用Python编写一个高效的端口扫描器的方法
Dec 20 Python
python多线程并发实例及其优化
Jun 27 Python
python matplotlib 画dataframe的时间序列图实例
Nov 20 Python
Python连接Oracle之环境配置、实例代码及报错解决方法详解
Feb 11 Python
浅谈TensorFlow之稀疏张量表示
Jun 30 Python
一文读懂Python 枚举
Aug 25 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
常见PHP数据库解决方案分析介绍
2015/09/24 PHP
CI框架封装的常用图像处理方法(缩略图,水印,旋转,上传等)
2016/11/22 PHP
基于php中echo用逗号和用点号的区别详解
2018/01/23 PHP
yii2.0框架数据库操作简单示例【添加,修改,删除,查询,打印等】
2020/04/13 PHP
基于jquery的固定表头和列头的代码
2012/05/03 Javascript
Js数组的操作push,pop,shift,unshift等方法详细介绍
2012/12/28 Javascript
用示例说明filter()与find()的用法以及children()与find()的区别分析
2013/04/26 Javascript
Jquery为a标签的href赋值实现代码
2013/05/03 Javascript
使用VS开发 Node.js指南
2015/01/06 Javascript
jQuery 遍历函数详解
2015/07/05 Javascript
javascript简单实现滑动菜单效果的方法
2015/07/27 Javascript
基于Jquery插件Uploadify实现实时显示进度条上传图片
2020/03/26 Javascript
JS之相等操作符详解
2016/09/13 Javascript
关于angular js_$watch监控属性和对象详解
2017/04/24 Javascript
9种改善AngularJS性能的方法
2017/11/28 Javascript
微信小程序如何获取用户信息
2018/01/26 Javascript
基于Vue实现微信小程序的图文编辑器
2018/07/25 Javascript
bootstrap自定义样式之bootstrap实现侧边导航栏功能
2018/09/10 Javascript
vue-cli3 从搭建到优化的详细步骤
2019/01/20 Javascript
[01:12:08]LGD vs OG 2019国际邀请赛淘汰赛 胜者组 BO3 第一场 8.24
2019/09/10 DOTA
使用Python3中的gettext模块翻译Python源码以支持多语言
2015/03/31 Python
python随机生成指定长度密码的方法
2015/04/04 Python
Python语言描述最大连续子序列和
2017/12/05 Python
Python设计模式之代理模式实例详解
2019/01/19 Python
Python垃圾回收机制三种实现方法
2020/04/27 Python
Under Armour安德玛德国官网:美国高端运动科技品牌
2019/03/09 全球购物
Shopbop中文官网:美国亚马逊旗下时尚购物网站
2020/12/15 全球购物
高三地理教学反思
2014/01/11 职场文书
《走一步再走一步》教学反思
2014/02/15 职场文书
2014年四风问题个人对照自查剖析材料
2014/09/15 职场文书
证券区域经理岗位职责
2015/04/10 职场文书
搞笑结婚保证书
2015/05/08 职场文书
2015年高三年级组工作总结
2015/07/21 职场文书
小学班级口号大全
2015/12/25 职场文书
如何制定销售人员薪酬制度?
2019/07/09 职场文书
SSM VUE Axios详解
2021/10/05 Vue.js