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 相关文章推荐
K-means聚类算法介绍与利用python实现的代码示例
Nov 13 Python
Python中将变量按行写入txt文本中的方法
Apr 03 Python
pandas.DataFrame 根据条件新建列并赋值的方法
Apr 08 Python
tensorflow实现简单的卷积神经网络
May 24 Python
Python使用cx_Freeze库生成msi格式安装文件的方法
Jul 10 Python
Pycharm配置远程调试的方法步骤
Dec 17 Python
Python3 单行多行万能正则匹配方法
Jan 07 Python
Python pandas DataFrame操作的实现代码
Jun 21 Python
PyQt5 QTableView设置某一列不可编辑的方法
Jun 25 Python
python threading和multiprocessing模块基本用法实例分析
Jul 25 Python
python实现贪吃蛇双人大战
Apr 18 Python
python 无损批量压缩图片(支持保留图片信息)的示例
Sep 22 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
从C/C++迁移到PHP——判断字符类型的函数
2006/10/09 PHP
php预定义变量使用帮助(带实例)
2013/10/30 PHP
C#使用PHP服务端的Web Service通信实例
2014/04/08 PHP
Yii2中添加全局函数的方法分析
2017/05/04 PHP
php使用curl获取header检测开启GZip压缩的方法
2018/08/15 PHP
ThinkPHP5与单元测试PHPUnit使用详解
2020/02/23 PHP
jQuery文本框(input textare)事件绑定方法教程
2013/04/24 Javascript
js禁止页面复制功能禁用页面右键菜单示例代码
2013/08/29 Javascript
JS保留两位小数,多位小数的示例代码
2014/01/07 Javascript
节点的插入之append()和appendTo()的用法介绍
2014/01/13 Javascript
php读取sqlite数据库入门实例代码
2014/06/25 Javascript
javascript实现表格增删改操作实例详解
2015/05/15 Javascript
js识别uc浏览器的代码
2015/11/06 Javascript
vue组件实践之可搜索下拉框功能
2018/11/25 Javascript
layui之table checkbox初始化时选中对应选项的方法
2019/09/02 Javascript
vue把输入框的内容添加到页面的实例讲解
2019/11/11 Javascript
Vue使用Proxy代理后仍无法生效的解决
2020/11/13 Javascript
详解Vue3 Teleport 的实践及原理
2020/12/02 Vue.js
[02:40]DOTA2殁境神蚀者 英雄基础教程
2013/11/26 DOTA
python使用cookie库操保存cookie详解
2014/03/03 Python
Python随机生成数模块random使用实例
2015/04/13 Python
python基础教程之五种数据类型详解
2017/01/12 Python
利用Anaconda完美解决Python 2与python 3的共存问题
2017/05/25 Python
用Python将一个列表分割成小列表的实例讲解
2018/07/02 Python
Python 中 function(#) (X)格式 和 (#)在Python3.*中的注意事项
2018/11/30 Python
快速解决docker-py api版本不兼容的问题
2019/08/30 Python
centos7中安装python3.6.4的教程
2019/12/11 Python
Tensorflow实现多GPU并行方式
2020/02/03 Python
师德师风个人反思
2014/04/28 职场文书
学校文明单位申报材料
2014/05/06 职场文书
图书馆志愿者活动总结
2014/06/27 职场文书
教师自查自纠工作情况报告
2014/10/29 职场文书
研究生论文答辩开场白
2015/05/27 职场文书
导游词之无锡丝业博物馆
2019/11/12 职场文书
python可视化之颜色映射详解
2021/09/15 Python
动画「半妖的夜叉姬」新BD特典图公开
2022/03/22 日漫