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中copy()方法的使用
May 21 Python
学习python之编写简单简单连接数据库并执行查询操作
Feb 27 Python
Python的Socket编程过程中实现UDP端口复用的实例分享
Mar 19 Python
Python中生成Epoch的方法
Apr 26 Python
Python实现查找匹配项作处理后再替换回去的方法
Jun 10 Python
Python实现的字典值比较功能示例
Jan 08 Python
python实现简单登陆系统
Oct 18 Python
python django生成迁移文件的实例
Aug 31 Python
用pandas划分数据集实现训练集和测试集
Jul 20 Python
python 19个值得学习的编程技巧
Aug 15 Python
python 如何实现遗传算法
Sep 22 Python
Python基于Tkinter开发一个爬取B站直播弹幕的工具
May 06 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
简单介绍下 PHP5 中引入的 MYSQLI的用途
2007/03/19 PHP
CI框架出现mysql数据库连接资源无法释放的解决方法
2016/05/17 PHP
Yii使用smsto短信接口的函数demo示例
2016/07/13 PHP
php显示页码分页类的封装
2017/06/08 PHP
php格式文件打开的四种方法
2018/02/24 PHP
PHPUnit测试私有属性和方法功能示例
2018/06/12 PHP
javascript while语句和do while语句的区别分析
2007/12/08 Javascript
24款非常有用的 jQuery 插件分享
2011/04/06 Javascript
表单的焦点顺序tabindex和对应enter键提交
2013/01/04 Javascript
浅析基于WEB前端页面的页面内容搜索的实现思路
2014/06/10 Javascript
$(document).ready(function() {})不执行初始化脚本
2014/06/19 Javascript
IE8下Jquery获取select选中的值post到后台报错问题
2014/07/02 Javascript
javascript求日期差的方法
2016/03/02 Javascript
js阻止默认浏览器行为与冒泡行为的实现代码
2016/05/15 Javascript
微信小程序 this和that详解及简单实例
2017/02/13 Javascript
Vue实现选择城市功能
2017/05/27 Javascript
React-intl 实现多语言的示例代码
2017/11/03 Javascript
Vue 动态组件components和v-once指令的实现
2019/08/30 Javascript
Python语言描述最大连续子序列和
2017/12/05 Python
Python引用计数操作示例
2018/08/23 Python
python 生成图形验证码的方法示例
2018/11/11 Python
使用pip安装python库的多种方式
2019/07/31 Python
pycharm配置git(图文教程)
2019/08/16 Python
Python:合并两个numpy矩阵的实现
2019/12/02 Python
Pandas的数据过滤实现
2021/01/15 Python
HTML5中微数据概述及在搜索引擎中的使用举例
2013/02/07 HTML / CSS
What's the difference between an interface and abstract class? (接口与抽象类有什么区别)
2012/10/29 面试题
医学院校毕业生自荐信范文
2014/01/01 职场文书
总经理司机职责
2014/02/02 职场文书
售后服务承诺书范文
2014/03/26 职场文书
优秀研究生主要事迹
2014/06/03 职场文书
公司股份合作协议书
2014/12/07 职场文书
政审证明材料
2015/06/19 职场文书
运动会宣传稿50字
2015/07/23 职场文书
Ajax是什么?Ajax高级用法之Axios技术
2021/04/21 Javascript
一小时学会TensorFlow2之基本操作2实例代码
2021/09/04 Python