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 相关文章推荐
pymssql ntext字段调用问题解决方法
Dec 17 Python
python逐行读取文件内容的三种方法
Jan 20 Python
在 Django/Flask 开发服务器上使用 HTTPS
Jul 03 Python
Python序列操作之进阶篇
Dec 08 Python
Python实现动态图解析、合成与倒放
Jan 18 Python
Django中的Signal代码详解
Feb 05 Python
python使用turtle绘制分形树
Jun 22 Python
Flask模板引擎之Jinja2语法介绍
Jun 26 Python
pycharm new project变成灰色的解决方法
Jun 27 Python
python异常触发及自定义异常类解析
Aug 06 Python
Python多线程及其基本使用方法实例分析
Oct 29 Python
Python requests模块安装及使用教程图解
Jun 30 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 Static关键字实用方法
2010/06/04 PHP
php模拟实现斗地主发牌
2020/04/22 PHP
php中数组最简单的使用方法
2020/12/27 PHP
jquery.validate使用攻略 第五步 正则验证
2010/07/01 Javascript
基于JavaScript实现仿京东图片轮播效果
2015/11/06 Javascript
Vue2.0组件间数据传递示例
2017/03/07 Javascript
深入理解vue-loader如何使用
2017/06/06 Javascript
JavaScript实现的简单加密解密操作示例
2018/06/01 Javascript
说说如何利用 Node.js 代理解决跨域问题
2019/04/22 Javascript
微信小程序之滑动页面隐藏和显示组件功能的实现代码
2020/06/19 Javascript
深入解析Python中函数的参数与作用域
2016/03/20 Python
Python2随机数列生成器简单实例
2017/09/04 Python
python实现多线程网页下载器
2018/04/15 Python
python之文件读取一行一行的方法
2018/07/12 Python
python ipset管理 增删白名单的方法
2019/01/14 Python
python 动态生成变量名以及动态获取变量的变量名方法
2019/01/20 Python
python处理大日志文件
2019/07/23 Python
Python将视频或者动态图gif逐帧保存为图片的方法
2019/09/10 Python
Python爬虫库requests获取响应内容、响应状态码、响应头
2020/01/25 Python
Python调用Windows命令打印文件
2020/02/07 Python
Python基于爬虫实现全网搜索并下载音乐
2021/02/14 Python
C++是不是类型安全的
2014/02/18 面试题
拾金不昧表扬信范文
2014/01/11 职场文书
护士辞职信范文
2014/01/19 职场文书
销售简历自我评价
2014/01/24 职场文书
采购主管岗位职责
2014/02/01 职场文书
党风廉设责任书
2014/04/16 职场文书
我为党旗添光彩演讲稿
2014/09/10 职场文书
社会主义核心价值观主题教育活动总结
2015/05/07 职场文书
学习新党章心得体会2016
2016/01/15 职场文书
2016年十一促销广告语
2016/01/28 职场文书
800字作文之大雪
2019/12/04 职场文书
JavaScript数组 几个常用方法总结
2021/11/11 Javascript
MongoDB支持的索引类型
2022/04/11 MongoDB
openEuler 搭建java开发环境的详细过程
2022/06/10 Servers
Win11 KB5015814遇安装失败 影响开始菜单性能解决方法
2022/07/15 数码科技