基本聊天程序

先来个基本的测试例子:

Main.py

from asyncore import dispatcher
import socket,asyncore
PORT = 11223
class ChatServer(dispatcher):
def __init__(self, port):
dispatcher.__init__(self)
self.create_socket(socket.AF_INET ,socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind(('',port))
self.listen(5)
def handle_accept(self):
conn,addr = self.accept()
print ('Connection attempt from',addr[0]) if __name__ == '__main__':
s = ChatServer(PORT)
try:asyncore.loop()
except KeyboardInterrupt:pass

上面是服务器段程序,接受到连接之后马上在服务器上显示对方IP,但是不保持连接。客户端测试的话很简单,可以自己写一个socket的连接,也可以为了省事直接本地开启telnet就行了,开启telnet的方法是,在开始菜单里搜索:

然后确定,之后cmd里直接telnet就行了。

运行上面的main.py,然后客户端链接服务端:

Cmd->telnet    : open 127.0.0.1 11223

上面就是一个最基本的Python服务器脚本流程。接下来实现一个基本的聊天程序用来练手。

实现的基本功能(虚拟茶会话) 测试环境python 3.6.0[python基础教程上的代码不能直接在3.6.0版本上跑,以下是改过的虚拟茶会话]

功能:

login name 登录房间

logout 退出房间

say   XXXX 发言

look 查看同一个房间内的人

who 查看谁登陆了当前服务器

测试截图

简单说下设计结构:

CommandHandler类 : 处理命令的,函数存在则执行,不存在则直接走unknown函数。结合着try和getattr函数python可以直接尝试去执行一个不确定存不存在的函数。[我一直在想,别的语言要怎么实现这个东西,是创建虚拟工厂?对了想起来了,干脆就创建一些函数,然后把函数名字格式化封装在一个void指针容器里的了。函数格式化要统一]

Room类:表示一个房间,里面有一些对房间人[链接]数据结构的增加删除操作,同时还有相关广播函数,用于把消息发给所有人。

LoginRoom类,里面有成功登陆房间,登陆房间失败以及登陆操作,比如问候登陆者,同时通知别人有人登陆等细节。

LogoutRoom类,登出房间类,用户登出房间时候进行的一些数据结构处理。

ChatRoom类,聊天室类,主要就是封装了一些功能函数。比如say look who等等。

ChatSession,ChatServer 类基本的服务器程序需要的,分别继承async_chat和dispatcher,处理一些服务器参数,以及重载设置一些处理函数等。

详细代码如下[注意本代码测试于python3.6.0]

#!/usr/bin/env python3
__author__ = 'tcstory'
from asyncore import dispatcher
from asynchat import async_chat
import socket, asyncore PORT=5005
NAME='TestChat' class EndSession(Exception): pass class CommandHandler:
'''
Simple command handler similar to cmd.Cmd from the standard library
''' def unknown(self, session, cmd):
'Respond to an unknown command'
session.push('Unkonw command: {0}\r\n'.format(cmd).encode()) def handle(self, session, line):
'Handle a received line from a given session'
if not line.strip():
return
#Split off the command
parts = line.split(' ', 1)
cmd = parts[0]
try:
line=parts[1].strip()
except IndexError:
line=''
#Try to find a handler
meth=getattr(self,'do_'+cmd,None)
try:
#Assume it's callable
meth(session,line)
except TypeError:
#If it isn't ,respond to the unknown command
self.unknown(session,cmd) class Room(CommandHandler):
'''
A generic environment that may contain one or more users(sessions).it takes care of basic command handling and broadcasting.
'''
def __init__(self,server):
self.server=server
self.sessions=[] def add(self,session):
'A session(user) has entered the room'
self.sessions.append(session) def remove(self,session):
'A session (user) has left the room'
self.sessions.remove(session) def broadcast(self,line):
'Send a line to all sessions in the room'
for session in self.sessions:
session.push(line.encode()) def do_logout(self,session,line):
'Respond to the logout command'
raise EndSession class LoginRoom(Room):
'''
A room meant for a single person who has just connected
''' def add(self,session):
Room.add(self,session)
#When a user enters,greet him/her
self.broadcast('Welcome to {0}\r\n'.format(self.server.name)) def unknown(self, session, cmd):
#All unknown commands (anything except login or logout)
#results in a prodding
session.push('Please log in\nUse "login <nick>"\r\n'.encode()) def do_login(self,session,line):
name=line.strip()
#Make sure the user has entered a name
if not name:
session.push('Please enter a name\r\n'.encode())
#Make sure that the name isn't in use
elif name in self.server.users:
session.push('The name {0} is taken.\r\n'.format(name).encode())
session.push('Please try again.\r\n'.encode())
else:
#The name is OK,os it is stored in the session.and
#the user is moved into the main room
session.name=name
session.enter(self.server.main_room) class ChatRoom(Room):
'''
A room meant for multiple users who can chat with the others in the room
''' def add(self,session):
#Notify everyone that a new user has entered
self.broadcast('{0} has entered the room.\r\n'.format(session.name))
self.server.users[session.name]=session
Room.add(self,session) def remove(self,session):
Room.remove(self,session)
#Notify everyone that a user has left
self.broadcast('{0} has left the room.\r\n'.format(session.name)) def do_say(self,session,line):
self.broadcast(('{0}: '+line+'\r\n').format(session.name)) def do_look(self,session,line):
'Handles the look command,used to see who is in a room'
session.push('The following are in this room:\r\n'.encode())
for other in self.sessions:
session.push('{0}\r\n'.format(other.name).encode()) def do_who(self,session,line):
'Handles the who command ,used to see who is logged in'
session.push('The following are logged in:\r\n'.encode())
for name in self.server.users:
session.push('{0}\r\n'.format(name).encode()) class LogoutRoom(Room):
'''
A simple room for a single user.Its sole purpose is to remove the user's name from the server
''' def add(self,session):
#When a session (user) enters the LogoutRoom it is deleted try:
del self.server.users[session.name]
except KeyError:
pass class ChatSession(async_chat):
'''
A single session,which takes care of the communication with a single user
''' def __init__(self,server,sock):
# async_chat.__init__(self,sock)
super().__init__(sock)
self.server=server
self.set_terminator(b'\r\n')
self.data=[]
self.name=None
#All sessions begin in a separate LoginRoom
self.enter(LoginRoom(server)) def enter(self,room):
# Remove self from current room and add self to next 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.decode('utf-8')) 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):
'''
A chat server with a single room
''' def __init__(self,port,name):
super().__init__()
# 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.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()

Python练习2-基本聊天程序-虚拟茶会话的更多相关文章

  1. 【Python】iichats —— 命令行下的局域网聊天程序

    转载请声明出处:http://www.cnblogs.com/kevince/p/3941728.html   ——By Kevince ii系列工具第三弹,命令行下的局域网聊天程序 原理: 程序启动 ...

  2. 通过编写聊天程序来熟悉python中多线程及socket的用法

    1.引言 Python中提供了丰富的开源库,方便开发者快速就搭建好自己所需要的应用程序.本文通过编写基于tcp/ip协议的通信程序来熟悉python中socket以及多线程的使用. 2.python中 ...

  3. python+soket实现 TCP 协议的客户/服务端中文(自动回复)聊天程序

    [吐槽] 网上的代码害死人,看着都写的言之凿凿,可运行就是有问题. 有些爱好代码.喜欢收藏代码的朋友,看到别人的代码就粘贴复制过来.可是起码你也试试运行看啊大哥 [正文] 昨日修改运行了UDP协议的C ...

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

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

  5. 使用Ajax long polling实现简单的聊天程序

    关于web实时通信,通常使用长轮询或这长连接方式进行实现. 为了能够实际体会长轮询,通过Ajax长轮询实现了一个简单的聊天程序,在此作为笔记. 长轮询 传统的轮询方式是,客户端定时(一般使用setIn ...

  6. Java网络编程以及简单的聊天程序

    网络编程技术是互联网技术中的主流编程技术之一,懂的一些基本的操作是非常必要的.这章主要讲解网络编程,UDP和Socket编程,以及使用Socket做一个简单的聊天软件. 全部代码下载:链接 1.网络编 ...

  7. python实现串口通讯小程序(GUI界面)

    python实现串口通讯小程序(GUI界面) 使用python实现串口通讯需要使用python的pyserial库来实现,这个库在安装python的时候没有自动进行安装,需要自己进行安装. 1.安装p ...

  8. Socket聊天程序——Common

    写在前面: 上一篇记录了Socket聊天程序的客户端设计,为了记录的完整性,这里还是将Socket聊天的最后一个模块--Common模块记录一下.Common的设计如下: 功能说明: Common模块 ...

  9. Socket聊天程序——客户端

    写在前面: 上周末抽点时间把自己写的一个简单Socket聊天程序的初始设计和服务端细化设计记录了一下,周二终于等来毕业前考的软考证书,然后接下来就是在加班的日子度过了,今天正好周五,打算把客户端的详细 ...

随机推荐

  1. 任务队列 与 Celery概述

    一.任务队列(Task Queues) 1.1 什么是任务队列? 任务队列用于管理后台工作,通常这些后台工作必须在 HTTP请求-响应循环 之外执行. 1.2 为什么需要任务队列? 对于那些不是由客户 ...

  2. 在C++中实现aligned_malloc

    malloc的默认行为 大家都知道C++中可以直接调用malloc请求内存被返回分配成功的内存指针,该指针指向的地址就是分配得到的内存的起始地址.比如下面的代码 int main() { void * ...

  3. 数据库索引知识到MySQL InnoDB

    前言 本文聊聊数据库中的索引,涉及索引基础数据结构,分类.以及使用索引的缺点. 索引就像一本书的目录,商场里面各个楼层指示图,让我们不需要自己无目的的找,而是能够很快的找到自己想要的. 1. 索引的基 ...

  4. FreeBSD 入门 哲学与玄学

    『哲学与玄学』 FreeBSD 是一种 UNIX 哲学(如模块化,一切皆文件等,见< UNIX 编程艺术>❩的发展,也是学院派的代表作品.她是一套工具集,她存在目的是为了让人们更好的生活. ...

  5. AmazonS3 使用AWS SDK for Java实现跨源资源共享 (CORS)

    CORS 配置 创建 CORS 配置并对存储桶设置该配置 通过添加规则来检索并修改配置 向存储桶添加修改过的配置 删除配置 import com.amazonaws.AmazonServiceExce ...

  6. HDU_5414 CRB and String 【字符串】

    一.题目 CRB and String 二.分析 对于这题,读懂题意非常重要. 题目的意思是在$s$的基础上,按题目中所描述的步骤,即在$s$中任意选择一个字符$c$,在这个字符后面添加一个不等于$c ...

  7. P1200_你的飞碟在这儿(JAVA语言)

    题目描述 众所周知,在每一个彗星后都有一只UFO.这些UFO时常来收集地球上的忠诚支持者. 不幸的是,他们的飞碟每次出行都只能带上一组支持者.因此,他们要用一种聪明的方案让这些小组提前知道谁会被彗星带 ...

  8. Unknown host 'd29vzk4ow07wi7.cloudfront.net'. You may need to adjust the proxy settings in Gradle.

    修改项目下build.gradle文件 在jcenter()前添加mavenCentral() 1 // Top-level build file where you can add configur ...

  9. N皇后求解。万万没想到,只用一个一维数组就搞定了。还体现了回溯。

    一.啥是N皇后?先从四皇后入手 给定一个4x4的棋盘,要在棋盘上放置4个皇后.他们的位置有这样的要求,每一列,每一行,每一对角线都能有一个皇后. 你可能会对这个对角线有疑惑,其实就是每一个小正方形的对 ...

  10. 在ASP.NET Core中用HttpClient(四)——提高性能和优化内存

    到目前为止,我们一直在使用字符串创建请求体,并读取响应的内容.但是我们可以通过使用流提高性能和优化内存.因此,在本文中,我们将学习如何在请求和响应中使用HttpClient流. 什么是流 流是以文件. ...