这个项目目的是编写一个聊天服务器,该聊天服务器的功能有:

服务器能同时接收来自不同用户的连接

允许用户同时操作

能够解释命令,例如,say或者logout命令

服务器容易扩展

这个项目里面我们会使用到的模块式asyncore,使用asyncore框架,程序可以处理同时连接多个用户。asyncore框架基于一些底层的机制,这些机制允许服务器逐个的对于连接上的用户进行服务。在处理下一个连接前,它并不读取当前用户的所有可用数据,而只读取一部分。除此之外,服务器只从那些需要读取数据的套接字中读取。程序就这样一遍遍的循环。写入操作同理。只使用socket和select模块就可以实现,但是asyncore和asynchat提供了一个可以处理所有细节的有用框架。

首先我们需要一个客户端来测试服务器,在windows下我们可以用telnet服务端,在unix内也可以用telnet。

初次实现:

首先我们需要创建两个类:一个作为聊天服务器,一个用于表示每个聊天会话(以连接用户)

要生成基本的ChatServer类,需要继承asyncore模块中的dispatcher类,dispatcher基本上就是一个套接字对象,但是可以利用它额外的事件处理特性。

下面是可以接受连接的服务器代码

 from asyncore import dispatcher
import socket, asyncore class ChatServer(dispatcher):
def handle_accept(self):
conn, addr = self.accept()
print 'Connection attempt from ',addr[0] s = ChatServer()
s.create_socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((''.5005))
s.listen(5)
asyncore.loop()

handle_accpet方法会调用允许客户端连接的self.accept函数。她会返回一个连接和一个地址。handle_accept方法知识打印有关连接尝试的信息。

当我们运行这个服务器并且用客户端连接他的时候,我们可以再服务器的控制台上看到返回的连接信息。

ChatSession类的主要任务是为每一个连接创建一个对象,该对象负责收集来自客户端的数据并且进行响应。我们可以自己继承dispatcher并且重写一些方法来实现这个功能,但是幸运的是已经有现成的模块能够完成绝大多数的工作,asynchat

下面便是一个简单的聊天服务器

 # -*- coding:utf-8 -*-
'''
xianghang
2015.4.9
虚拟聊天室
''' from asyncore import dispatcher
from asynchat import async_chat
import socket, asyncore PORT = 5005
NAME = 'TestChat'
class ChatSessioin(async_chat):
'''
处理服务器和一个用户之间连接的类
'''
def __init__(self, server, sock):
#标准设置任务
async_chat.__init__(self, sock)
self.server = server
self.set_terminator('\r\n')
self.data = []
#问候用户
self.push('Welcome to %s\r\n' % self.server.name) def collect_incoming_data(self, data):
self.data.append(data) def found_terminator(self):
'''
如果发现了一个终止对象,也就意味着读入了一个完整的行,将广播给所有人
'''
line = ''.join(self.data)
self.data = []
self.server.broadcast(line) def handle_close(self):
async_chat.handle_close(self)
self.server.disconnect(self) class ChatServer(dispatcher):
'''
接收连接并且产生单个会话的类。他还会处理到其他会话的广播
'''
def __init__(self, port, name):
#标准设置任务
dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind(('', port))
self.listen(5)
self.name = name
self.sessions = []
def disconnect(self, session):
self.sessions.remove(session) def broadcast(self, line):
for session in self.sessions:
session.push(line+'\r\n') def handle_accept(self):
conn, addr = self.accept()
self.sessions.append(ChatSessioin(self, conn)) if __name__ == '__main__':
s = ChatServer(PORT, NAME)
try: asyncore.loop()
except KeyboardInterrupt: print

运行这个程序后会发现,客户端虽然能够显示其它用户发送的信息,但不能识别是哪一个用户,而且整个程序没有登录登出等功能,下面我们就来扩展这些功能。

再次实现:

首先我们把服务器分为三个房间,登录房间,聊天室,登出房间,三个房间分别为三个类,这些类的父类拥有添加和删除会话 的功能。代码如下

 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):
'响应logout命令'
raise EndSession

登录房间继承room父类

 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):
#所有未知命令(除了login或者logout除外)
#会导致一个警告
session.push('Please log in \nUse "login <nick>"\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)
session.push('Please try again.\r\n')
else:
#名字没问题,所以存储在会话中
#将用户移动到主聊天室
session.name = name
session.enter(self.server.main_room)

  登录房间是让用户登录时所在的房间,在该房间内接收用户的登录命令,登陆成功后进入聊天房间。同样的,也有登出房间登出房间同理。

  聊天室房间负责处理say,look命令,say命令可以让用户在该房间内发言,并显示在其他的客户端上;look命令可以让用户查看当前聊天室所存在的用户。

 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):
'处理look命令,该命令用于查看谁在房间'
session.push('The following are in this room:\r\n')
for other in self.sessions:
session.push(other.name + '\r\n')

整个服务器程序的结构如下图:

python实现虚拟茶话会的更多相关文章

  1. python基础教程项目五之虚拟茶话会

    python基础教程项目五之虚拟茶话会 几乎在学习.使用任何一种编程语言的时候,关于socket的练习从来都不会少,尤其是会写一些局域网的通信的东西.所以书上的这个项目刚好可以练习一下socket编程 ...

  2. 创建 Python Virtualenv 虚拟隔离环境

    video:创建 Python Virtualenv 虚拟隔离环境 python 虚拟环境 venv 简单用法 - littlemore - 博客园 创建 Python Virtualenv 虚拟隔离 ...

  3. python基础教程总结15——5 虚拟茶话会

    聊天服务器: 服务器能接受来自不同用户的多个连接: 允许用户同时(并行)操作: 能解释命令,例如,say或者logout: 容易拓展 套接字和端口: 套接字是一种使用标准UNIX文件描述符(file ...

  4. [译]Python编写虚拟解释器

    使用Python编写虚拟机解释器 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiyanlou,密码shiyanlou 2. 环境介绍 本实验环境采用带桌面的Ubuntu Linux环 ...

  5. Python之虚拟环境管理

    Python本身有很多个版本,第三方的Python包又有很多可用的版本,所以经常会遇到下面的问题: 运行不同的Python程序,需要使用不同版本的Python(2.x或3.x). 在同一中Python ...

  6. faker之python构造虚拟数据

    python中可以使用faker来制造一些虚拟数据 首选安装faker pip install Faker 老版的叫法是faker-factory,但是已不适用 使用faker.Factory.cre ...

  7. 【python】虚拟环境管理之 virtualenv 、pipenv

    虚拟环境介绍 应用场景 python在安装第三方包时,会被pip安装到/site-package下,如果我们需要同时维护多个python项目,那这些项目都会共用一个python,而真实需求是多个项目之 ...

  8. python的虚拟运行环境

    Python 虚拟环境:Virtualenv 博客分类: Python python 在进行python开发的时候避免不同版本python或python不同版本组件之间的冲突, 有必要配置python ...

  9. python的虚拟环境管理工具venv使用方法介绍及与nodejs的包管理方式对比

    一.nodejs 包管理方式 我们知道, nodejs的包管理工具npm可以安装项目所需要的包,安装方法及区别如下: npm i module_name -g 全局安装 npm i module_na ...

随机推荐

  1. php学习笔记:读取文档的内容,利用php修改文档内容

    直接上代码 <?php /** * Created by PhpStorm. * User: Administrator * Date: 2016/9/10 0010 * Time: 20:27 ...

  2. Windows程序==>>使用ListView控件展示数据

    使用ListView控件展示数据 01.ImageList控件 1.了解了解         属性 说明 Images 储存在图像列表中的所有图像 ImageSize 图像列表中图像的大小 Trans ...

  3. Asp.Net MVC开源论坛中文版

    支持多国语言 支持多种数据库,开盖即饮(因为EF支持),无需安装. 积分 等级 权限 角色 标签 Rss 表情 附件 审核 问答 投票 收藏 日志 排行榜与热点 主题,默认Bootstrap响应式 最 ...

  4. .Net开源项目之开源论坛

    .Net开源项目非常多,但是开源并且直接就能用的BBS项目就很少了,至少最近我在这上面没有找到一个合适的开源论坛.可能是因为我要求比较特殊,不但要开箱即用,还要用MVC+MySql开发. Discuz ...

  5. MySQL Cluster配置概述

    一.     MySQL Cluster概述 MySQL Cluster 是一种技术,该技术允许在无共享的系统中部署“内存中”数据库的 Cluster .通过无共享体系结构,系统能够使用廉价的硬件,而 ...

  6. Oracle执行计划与统计信息的一些总结

    [日期:2011-08-05]来源:Linux社区  作者:wangshengfeng1986211[字体:大 中 小] 2010-07-01 15:03 1.SET AUTOTRACE ON EXP ...

  7. 转:NLog 自定义日志内容,写日志到数据库;修改Nlog.config不起作用的原因

    转:http://www.cnblogs.com/tider1999/p/4308440.html NLog的安装请百度,我安装的是3.2.NLog可以向文件,数据库,邮件等写日志,想了解请百度,这里 ...

  8. OC 复合 组装电脑

    键盘类 #import <Foundation/Foundation.h> @interface Keyboard : NSObject @property(strong,nonatomi ...

  9. IOS 欢迎页(UIScrollView,UIPageControl)

    本文介绍了app欢迎页的简单实现.只有第一次运行程序时才说会出现,其余时间不会出现.下面是效果图. 代码如下:(如有不明白的可以评论我,我会详细讲解) // // ViewController.m / ...

  10. 真机测试时的错误:No matching provisioning profiles found

    1.出现错误的原因是这样的---- 公司开始做项目,原来做真机测试的时候,用的是公司申请的苹果开发者账号.现在项目结束了,准备上线,但客户要求使用客户自己的苹果开发者是账号上线,于是就用客户的账号测试 ...