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安装第三方库的3种方法
Jun 21 Python
Django中反向生成models.py的实例讲解
May 30 Python
Python退火算法在高次方程的应用
Jul 26 Python
python随机在一张图像上截取任意大小图片的方法
Jan 24 Python
python dataframe NaN处理方式
Dec 26 Python
Python字符串中删除特定字符的方法
Jan 15 Python
python自动点赞功能的实现思路
Feb 26 Python
浅析NumPy 切片和索引
Sep 02 Python
Python绘制组合图的示例
Sep 18 Python
学生如何注册Pycharm专业版以及pycharm的安装
Sep 24 Python
通用的Django注册功能模块实现方法
Feb 05 Python
python playwright 自动等待和断言详解
Nov 27 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调用Twitter的RSS的实现代码
2010/03/10 PHP
PHP页面间参数传递的四种方法详解
2013/06/09 PHP
服务器迁移php版本不同可能诱发的问题
2015/12/22 PHP
PHP下载远程图片并保存到本地方法总结
2016/01/22 PHP
微信公众平台开发教程⑥ 微信开发集成类的使用图文详解
2019/04/10 PHP
通过修改referer下载文件的方法
2008/05/11 Javascript
javascript读写XML实现广告轮换(兼容IE、FF)
2013/08/09 Javascript
javascript窗口宽高,鼠标位置,滚动高度(详细解析)
2013/11/18 Javascript
JavaScript中最简洁的编码html字符串的方法
2014/10/11 Javascript
JS验证邮件地址格式方法小结
2015/12/01 Javascript
JavaScript 函数的执行过程
2016/05/09 Javascript
Bootstrap基本插件学习笔记之轮播幻灯片(23)
2016/12/08 Javascript
详解用原生JavaScript实现jQuery的某些简单功能
2016/12/19 Javascript
jQuery实现元素的插入
2017/02/27 Javascript
Spring Boot+AngularJS+BootStrap实现进度条示例代码
2017/03/02 Javascript
Node.JS更改Windows注册表Regedit的方法小结
2017/08/18 Javascript
AngularJS动态添加数据并删除的实例
2018/02/27 Javascript
webpack 样式加载的实现原理
2018/06/12 Javascript
vue2.0 中使用transition实现动画效果使用心得
2018/08/13 Javascript
vue使用require.context实现动态注册路由
2020/12/25 Vue.js
[03:11]2014DOTA2国际邀请赛-VG掉入败者组 独家专访357
2014/07/19 DOTA
[11:44]Ti9 OG夺冠时刻
2019/08/25 DOTA
python根据距离和时长计算配速示例
2014/02/16 Python
解决出现Incorrect integer value: '' for column 'id' at row 1的问题
2017/10/29 Python
Django admin实现图书管理系统菜鸟级教程完整实例
2017/12/12 Python
python组合无重复三位数的实例
2018/11/13 Python
把JSON数据格式转换为Python的类对象方法详解(两种方法)
2019/06/04 Python
Python批量处理csv并保存过程解析
2020/05/16 Python
CSS3实现精美横向滚动菜单按钮
2017/04/14 HTML / CSS
三严三实对照检查材料范文
2014/09/23 职场文书
公司2014年度工作总结
2014/12/10 职场文书
先进班组材料范文
2014/12/25 职场文书
2015年世界无烟日活动方案
2015/05/04 职场文书
2015年行政管理人员工作总结
2015/10/15 职场文书
2016年党员公开承诺书格式范文
2016/03/24 职场文书
golang生成vcf通讯录格式文件详情
2022/03/25 Golang