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的迭代器和生成器
Jul 29 Python
Python编程中字符串和列表的基本知识讲解
Oct 14 Python
python 简单备份文件脚本v1.0的实例
Nov 06 Python
Python流程控制 if else实现解析
Sep 02 Python
如何使用python3获取当前路径及os.path.dirname的使用
Dec 13 Python
python通过移动端访问查看电脑界面
Jan 06 Python
tensorboard实现同时显示训练曲线和测试曲线
Jan 21 Python
Python连接Hadoop数据中遇到的各种坑(汇总)
Apr 14 Python
通过python 执行 nohup 不生效的解决
Apr 16 Python
tensorflow 20:搭网络,导出模型,运行模型的实例
May 26 Python
python适合做数据挖掘吗
Jun 16 Python
pytorch 实现变分自动编码器的操作
May 24 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
linux php mysql数据库备份实现代码
2009/03/10 PHP
thinkphp框架page类与bootstrap分页(美化)
2017/06/25 PHP
一次因composer错误使用引发的问题与解决
2019/03/06 PHP
JQuery 图片延迟加载并等比缩放插件
2009/11/09 Javascript
window.location.hash 使用说明
2010/11/08 Javascript
Javascript 拖拽雏形中的一些问题(逐行分析代码,让你轻松了拖拽的原理)
2015/01/23 Javascript
js实现touch移动触屏滑动事件
2015/04/17 Javascript
谈谈Jquery ajax中success和complete有哪些不同点
2015/11/20 Javascript
详解页面滚动值scrollTop在FireFox与Chrome浏览器间的兼容问题
2015/12/03 Javascript
JavaScript面试题大全(推荐)
2016/09/22 Javascript
Bootstrap Table从服务器加载数据进行显示的实现方法
2016/09/29 Javascript
Nodejs进阶:如何将图片转成datauri嵌入到网页中去实例
2016/11/21 NodeJs
js replace()去除代码中空格的实例
2017/02/14 Javascript
如何使用Bootstrap创建表单
2017/03/29 Javascript
基于js Canvas实现二次贝塞尔曲线
2018/12/25 Javascript
vue读取本地的excel文件并显示在网页上方法示例
2019/05/29 Javascript
ElementUI Tag组件实现多标签生成的方法示例
2019/07/08 Javascript
vue 开发之路由配置方法详解
2019/12/02 Javascript
python实现上传样本到virustotal并查询扫描信息的方法
2014/10/05 Python
Python实现的tab文件操作类分享
2014/11/20 Python
python获取远程图片大小和尺寸的方法
2015/03/26 Python
python复制列表时[:]和[::]之间有什么区别
2018/10/16 Python
Python实现定时自动关闭的tkinter窗口方法
2019/02/16 Python
python多线程抽象编程模型详解
2019/03/20 Python
python不同系统中打开方法
2020/06/23 Python
详解android与HTML混合开发总结
2018/06/06 HTML / CSS
Hobbs官方网站:英国奢华女性时尚服装
2020/02/22 全球购物
毕业生应聘幼儿园的自荐信
2013/11/20 职场文书
自我评价优秀范文分享
2013/11/30 职场文书
最新奶茶店创业计划书范文
2014/02/08 职场文书
超市促销活动方案
2014/03/05 职场文书
协议书模板
2014/04/23 职场文书
优秀团员事迹材料1000字
2014/08/20 职场文书
九一八事变纪念日演讲稿
2014/09/14 职场文书
售后服务承诺函格式
2015/01/21 职场文书
优质护理心得体会
2016/01/22 职场文书