python练习四—简单的聊天软件
python最强大的是什么?库支持!!有了强大的库支持,一个简单的聊天软件实现就更简单了,本项目思路如下
# 项目思路
1. 服务器的工作
* 初始化服务器
* 新建一个聊天房间
* 维护一个已链接用户的会话列表
* 维护一个已登录用户的字典,用户名和会话
* 监听端口,接受会话,并启动一个ChatSession处理 2. 会话线程
* 初始化一个接收数据缓冲区
* 处理用户输入的命令,并提醒用户先登录(也就是说目前指处理登陆命令)
* 将用户输入的数据加入缓冲区
* 用户一次输入结束后,将缓冲区数据发送,并清空缓冲区 3. 命令分发
* 对用的输入进行分割,并将对应的命令分发到相应的处理函数,如果没有则采用默认处理函数 4. 房间,继承自命令分发类,即:具有处理命令能力的房间 5. LoginRoom,继承自Room,处理登陆相关的命令
* 加入房间,有用户进入房间,欢迎该用户
* 登录命令,登陆成功之后进入房间,将该session加入队列 6. ChatRoom,继承自Room,处理发言、查看所有用户等命令 7. LogoutRoom,继承自Room,处理用户登出,相当于用户输入登出命令之后进入一个房间,
然后抛出异常通知ChatSession关闭线程
代码如下:
#! /usr/bin/env python
# -*- coding=utf-8 -*- from asyncore import dispatcher
import socket
import asyncore
from asynchat import async_chat # 服务器监听端口号
PORT = 5005
# 服务器名称
NAME = 'QQ' class EndException(Exception):
pass class CommandHandler:
'''
用来处理用户输入简单的命令
''' def unknown(self, session, cmd):
'''处理未知命令'''
session.push('Unknown command %s\r\n' %cmd) def handler(self, session, line):
'''
处理命令(命令路由),根据用户输入分析储命令,调用对应的处理程序
'''
if not line.strip():
# 如果输入为空,返回,不做处理
return
# 切分命令
print line + '----------'
parts = line.split(' ', 1)
cmd = parts[0]
try:
line = parts[1]
except IndexError:
line = ''
method = getattr(self, 'do_' + cmd, None)
try:
method(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, sessioni, line):
'用户退出房间'
raise EndException class LoginRoom(Room):
'''
用户登录房间,处理用户登录房间的一些操作
''' def add(self, session):
'扩展父类方法,在加入房间之后,给用户发送欢迎语'
Room.add(self, session)
session.push('welcome to %s \r\n' % self.server.name) def unknown(self, session, cmd):
'处理未知命令,提示用户输入登录命令'
session.push('please log in \r "Use login <nick>" \r\n') def do_login(self, session, line):
'处理用户登录命令'
name = line.strip()
if not name:
# 如果没有输入名称,提示用户输入
session.push('Please input a name')
elif name in self.server.users:
# 如果名称已被占用
session.push('the % is taken \r\n' %name)
session.push('Please try again')
else:
# 如果正常则让用户进入房间
session.name = name
session.enter(self.server.main_room) class ChatRoom(Room):
'''
聊天房间,处理用户在房间中聊天的命令
''' def add(self, session):
'用户进入聊天房间的时候,通知其他用户'
Room.add(self, session)
self.broadcast('%s has enter in the room \r\n' %session.name)
self.server.users[session.name] = session def remove(self, session):
'提醒其他用户,xx离开房间'
Room.remove(self, session)
self.broadcast('%s has left the room \r\n' %session.name) def do_say(self, session, line):
'用户发言'
self.broadcast(session.name + ':' + line + '\r\n') def do_look(self, session, line):
'查看房间中所有用户'
self.broadcast('the following are in the room: \r\n')
for user in self.sessions:
self.broadcast(user.name + '\r\n') class LogoutRoom(Room):
'''
用户退出房间,所需要的命令
''' def do_logout(self, session, line):
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(self.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.handler(self, line)
except EndException:
self.handle_close() def handle_close(self):
async_chat.handle_close(self)
self.enter(LogoutRoom(self)) class ChatServer(dispatcher):
'''
服务器,负责接受客户端链接并分配给具体的程序(线程处理)
''' def __init__(self, port, name):
'初始化服务器,初始会话列表,初始化用户字典(用户名对应用户session),初始化服务器主房间'
dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind(('', port))
self.listen(5)
self.sessions = []
self.users = {}
self.name = name
self.main_room = ChatRoom(self) def handle_accept(self):
conn, addr = self.accept()
print 'connection attemp from ', addr[0]
ChatSession(self, conn) s = ChatServer(PORT, NAME)
try:
asyncore.loop()
except KeyboardInterrupt:
pass
其实从第一个练习开始我就开始意识到,书中的引导是逐步的——使用的是迭代式的开发,一开始知识一个简单的例子视线了基本的功能,然后基于简单的列子将代码模块化,逐渐加功能,我也是试着这样做的,但是鉴于篇幅,其他代码就没有贴上来,在完整的代码可以下载
再进行本练习中,有一下基础知识得到巩固:
# 判断正在运行的模块是直接运行还是被import执行的,即:
# 直接运行的话__name='__main__'
# 如果是import的话就不是__main__
if __name__ == '__main__': # 变量作用域
data = 123
* 在函数内部申明,作用域就是函数内部,
* 在类内部申明就是类变量,访问的时候直接data
* 在类内部的函数内部申明如:self.data=124,调用的时候只能是self.data,如果使用data,默认查找的是全局变量
* 如果不适用self指明,python默认调用的全局变量
* python变量可以重名,在同一作用于内如果已经定义过,只是进赋值 # 在子类方法内部调用父类方法(如:Room父类,ChatRoom子类)
Room.__init__()
完整代码
http://pan.baidu.com/s/1nu5KE4T
python练习四—简单的聊天软件的更多相关文章
- 通过python 构建一个简单的聊天服务器
构建一个 Python 聊天服务器 一个简单的聊天服务器 现在您已经了解了 Python 中基本的网络 API:接下来可以在一个简单的应用程序中应用这些知识了.在本节中,将构建一个简单的聊天服务器.使 ...
- 【Python网络编程】多线程聊天软件程序
课程设计的时候制作的多线程聊天软件程序 基于python3.4.3 import socket import pickle import threading import tkinter import ...
- Netty学习笔记(四) 简单的聊天室功能之服务端开发
前面三个章节,我们使用了Netty实现了DISCARD丢弃服务和回复以及自定义编码解码,这篇博客,我们要用Netty实现简单的聊天室功能. Ps: 突然想起来大学里面有个课程实训,给予UDP还是TCP ...
- python使用websocket简单组建聊天室
server端 ###websocket_server### import socket import threading sock = socket.socket(socket.AF_INET, s ...
- 用python实现一个简单的聊天功能,tcp,udp,socketserver版本
基于tcp协议版本 服务器端 import socket server = socket.socket() server.bind(('127.0.0.1', 8001)) server.listen ...
- Python Socket实现简单的聊天室
通过参考其他牛人的文章和代码, 再根据自己的理解总结得出, 说明已经加在注释中, FYI 主要参考文章: http://blog.csdn.net/dk_zhe/article/details/3 ...
- 使用python编写的简单远程管理软件
因为用户可以选择是否同意被控制,所以并不算是木马. 使用python3.7,spyder,在windows 10 开发. client为控制端,server为被控端. 参考 mygithub http ...
- python实现简单的聊天小程序
概要 这是一个使用python实现一个简单的聊天室的功能,里面包含群聊,私聊两种聊天方式.实现的方式是使用套接字编程的一个使用TCP协议 c/s结构的聊天室 实现思路 x01 服务端的建立 首先,在服 ...
- Java实现 简单聊天软件
简单的聊天软件 //客户端 package yjd9; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; ...
随机推荐
- 【翻译】Flume 1.8.0 User Guide(用户指南) Processors
翻译自官网flume1.8用户指南,原文地址:Flume 1.8.0 User Guide 篇幅限制,分为以下5篇: [翻译]Flume 1.8.0 User Guide(用户指南) [翻译]Flum ...
- Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring
Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring 非原创[只为记录],原博文地址:https://www.cnblogs.com/ ...
- HDU 6382 odds (暴力 + 剪枝优化)
odds Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Subm ...
- HTML5中input标签有用的新属性
HTML5对input增加了一些新标签,个人觉得比较常用有效的以下几个 placeholder=“请输入” 常见用于默认提示 autofocus 自动聚焦到当前输入框 maxlength=" ...
- 【python-时间戳】时间与时间戳之间的转换
对于时间数据,如2016-05-05 20:28:54,有时需要与时间戳进行相互的运算,此时就需要对两种形式进行转换,在Python中,转换时需要用到time模块,具体的操作有如下的几种: 将时间转换 ...
- 新特技软件(Analyzer)添加新用户
新特技软件添加新用户的步骤比较多,记录下来,方便以后使用 安装完软件,处理好自己的AS以后,准备添加用户 步骤一: 我们要在安装Analyzer的服务器上添加新的Windows用户 步骤二:在Anal ...
- 从NoSQL到NewSQL,谈交易型分布式数据库建设要点
在上一篇文章<从架构特点到功能缺陷,重新认识分析型分布式数据库>中,我们完成了对不同"分布式数据库"的横向分析,本文Ivan将讲述拆解的第二部分,会结合NoSQL与Ne ...
- 刺透内网的HTTP代理
从偶然出发 在做测试的时候发现了这样一个漏洞,原请求报文如下: GET / HTTP/1.1 Host: attack_website [... HEADER ...] ... 当时最初目的是想测SS ...
- IM群聊消息的已读回执功能该怎么实现?
本文引用了架构师之路公众号作者沈剑的文章,内容有改动,感谢原作者. 1.前言 我们平时在使用即时通讯应用时候,每当发出一条聊天消息,都希望对方尽快看到,并尽快回复,但对方到底有没有真的看到?我却并不知 ...
- Win10下python不同版本同时安装并解决pip共存问题
特别说明,本文是在Windows64位系统下进行的,32位系统请下载相应版本的安装包,安装方法类似. 使用python开发,环境有Python2和 python3 两种,有时候需要两种环境切换使用,下 ...