构建一个 Python 聊天服务器

一个简单的聊天服务器

现在您已经了解了 Python 中基本的网络 API;接下来可以在一个简单的应用程序中应用这些知识了。在本节中,将构建一个简单的聊天服务器。使用 Telnet,客户机可以连接到 Python 聊天服务器上,并在全球范围内相互进行通信。提交到聊天服务器的消息可以由其他人进行查看(以及一些管理信息,例如客户机加入或离开聊天服务器)。这个模型如图 1 所示。

图 1. 聊天服务器使用 select 方法来支持任意多个客户机

聊天服务器的一个重要需求是必须可以伸缩。服务器必须能够支持任意个流(TCP)客户机。

要支持任意个客户机,可以使用 select 方法来异步地管理客户机的列表。不过也可以使用服务器 socket 的 select 特性。select 的读事件决定了一个客户机何时有可读数据,而且它也可以用来判断何时有一个新客户机要连接服务器 socket 了。可以利用这种行为来简化服务器的开发。

接下来,我们将展示聊天服务器的 Python 源代码,并说明 Python 怎样帮助简化这种实现。

ChatServer 类

让我们首先了解一下 Python 聊天服务器类和 __init__ 方法 —— 这是在创建新实例时需要调用的构造函数。

这个类由 4 个方法组成。run 方法用来启动服务器,并且允许客户机的连接。broadcast_string 和 accept_new_connection 方法在类内部使用,我们稍后就会讨论。

__init__ 方法是一个特殊的方法,它们会在创建一个类的新实例时调用。注意所有的方法都使用一个 self 参数,这是对这个类实例本身的引用(与 C++ 中的 this 参数非常类似)。这个 self 参数是所有实例方法的一部分,此处用来访问实例变量。

__init__ 方法创建了 3 个实例变量。port 是服务器的端口号(传递给构造函数)。srvsock 是这个实例的 socket 对象,descriptors 是一个列表,包含了这个类中的每个 socket 对象。可以在 select 方法中使用这个列表来确定读事件的列表。

最后,清单 16 给出了 __init__ 方法的代码。在创建一个流 socket 之后,就可以启用 SO_REUSEADDR socket 选项了;这样如果需要,服务器就可以快速重新启动了。通配符地址被绑定到预先定义好的端口号上。然后调用 listen 方法,从而允许到达的连接接入。服务器 socket 被加入到descriptors 列表中(现在只有一个元素),但是所有的客户机 socket 都可以在到达时被加入到这个列表中(请参阅 accept_new_connection)。此时会在 stdout 上打印一条消息,说明这个服务器已经被启动了。

清单 16. ChatServer 类的 init 方法

import socket
import selectclass ChatServer:def __init__( self, port ):self.port = port;self.srvsock = socket.socket( socket.AF_INET, socket.SOCK_STREAM )self.srvsock.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )self.srvsock.bind( ("", port) )self.srvsock.listen( 5 )self.descriptors = [self.srvsock]print 'ChatServer started on port %s' % portdef run( self ):...def broadcast_string( self, str, omit_sock ):...def accept_new_connection( self ):...

run 方法对于聊天服务器来说是一个循环(请参阅清单 17)。在调用时,它还会进入一个无限循环,并在连接的客户机之间进行通信。run 方法

服务器的核心是 select 方法。我将 descriptor 列表(其中包含了所有服务器的 socket)作为读事件的列表传递给 select (写事件和异常事件列表都为空)。当检测到读事件时,它会作为 sread 返回。(我们忽略了 swrite 和 sexc 列表。)sread 列表包含要服务的 socket 对象。我们循环遍历这个 sread 列表,检查每个找到的 socket 对象。

在这个循环中首先检查 socket 对象是否是服务器。如果是,就说明一个新的客户机正在试图连接,这就要调用 accept_new_connection 方法。否则,就读取客户机的 socket。如果 recv 返回 NULL,那就关闭 socket。

在这种情况中,我们构建了一条消息,并将其发送给所有已经连接的客户机,然后关闭 socket,并从 descriptor 列表中删除对应的对象。如果 recv 返回值不是 NULL,那么就说明已经有消息可用了,它被存储在 str 中。这条消息会使用 broadcast_string 发送给其他所有的客户机。

清单 17. 聊天服务器的 run 方法是这个聊天服务器的核心

def run( self ):while 1:# Await an event on a readable socket descriptor(sread, swrite, sexc) = select.select( self.descriptors, [], [] )# Iterate through the tagged read descriptorsfor sock in sread:# Received a connect to the server (listening) socketif sock == self.srvsock:self.accept_new_connection()else:# Received something on a client socketstr = sock.recv(100)# Check to see if the peer socket closedif str == '':host,port = sock.getpeername()str = 'Client left %s:%s\r\n' % (host, port)self.broadcast_string( str, sock )sock.closeself.descriptors.remove(sock)else:host,port = sock.getpeername() newstr = '[%s:%s] %s' % (host, port, str) self.broadcast_string( newstr, sock ) 

辅助方法

在这个聊天服务器中有两个辅助方法,提供了接收新客户机连接和将消息广播到已连接的客户机上的功能。

当在到达连接队列中检测到一个新的客户机时,就会调用 accept_new_connection 方法(请参阅清单 18)。accept 方法用来接收这个连接,它会返回一个新的 socket 对象,以及远程地址信息。我们会立即将这个新的 socket 加入到 descriptors 列表中,然后向这个新的客户机输出一条消息欢迎它加入聊天。我创建了一个字符串来表示这个客户机已经连接了,使用 broadcast_string 方法来成组地广播这条消息(请参阅清单 19)。

注意,除了要广播的字符串之外,还要传递一个 socket 对象。原因是我们希望有选择地忽略一些 socket,从而只接收特定的消息。例如,当一个客户机向一个组中发送一条消息时,这条消息应该发送给这个组中除了自己之外的所有人。当我们生成状态消息来说明有一个新的客户机正在加入该组时,这条消息也不应该发送给这个新客户机,而是应该发送给其他所有人。这种任务是在 broadcast_string 中使用 omit_sock 参数实现的。这个方法会遍历 descriptors 列表,并将这个字符串发送给那些不是服务器 socket 且不是 omit_sock 的 socket。

清单 18. 在聊天服务器上接收一个新客户机连接

def accept_new_connection( self ):newsock, (remhost, remport) = self.srvsock.accept()self.descriptors.append( newsock )newsock.send("You're connected to the Python chatserver\r\n")str = 'Client joined %s:%s\r\n' % (remhost, remport)self.broadcast_string( str, newsock )

清单 19. 将一条消息在聊天组中广播

def broadcast_string( self, str, omit_sock ):for sock in self.descriptors:if sock != self.srvsock and sock != omit_sock:sock.send(str)print str,

实例化一个新的 ChatServer

现在您已经看到了 Python 聊天服务器(这只使用了不到 50 行的代码),现在让我们看一下如何在 Python 中实例化一个新的聊天服务器。

我们通过创建一个新的 ChatServer 对象来启动一个服务器(传递要使用的端口号),然后调用 run 方法来启动服务器并允许接收所有到达的连接:

清单 20. 实例化一个新的聊天服务器

myServer = ChatServer( 2626 )
myServer.run()

现在,这个服务器已经在运行了,您可以从一个或多个客户机连接到这个服务器上。也可以将几个方法串接在一起来简化这个过程(如果需要简化的话):

清单 21. 串接几个方法

myServer = ChatServer( 2626 ).run()

这可以实现相同的结果。下面我们将展示 ChatServer 类的用法。

展示 ChatServer

下面就是 ChatServer 的用法。我们将展示 ChatServer 的输出结果(请参阅清单 22 )以及两个客户机之间的对话(请参阅清单 23 和 清单 24)。用户输入的文本以黑体形式表示。

清单 22. ChatServer 的输出

[plato]$ python pchatsrvr.py
ChatServer started on port 2626
Client joined 127.0.0.1:37993
Client joined 127.0.0.1:37994
[127.0.0.1:37994] Hello, is anyone there?
[127.0.0.1:37993] Yes, I'm here.
[127.0.0.1:37993]  Client left 127.0.0.1:37993

清单 23. 聊天客户机 #1 的输出

[plato]$ telnet localhost 2626
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
You're connected to the Python chatserver
Client joined 127.0.0.1:37994
[127.0.0.1:37994] Hello, is anyone there?
Yes, I'm here.^]
telnet> close
Connection closed.
[plato]$

清单 24. 聊天客户机 #2 的输出

[plato]$ telnet localhost 2626
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
You're connected to the Python chatserver
Hello, is anyone there?
[127.0.0.1:37993] Yes, I'm here.
[127.0.0.1:37993] Client left 127.0.0.1:37993

正如您在清单 22 中看到的那样,所有客户机之间的对话都会显示到 stdout 上,包括客户机的连接和断开消息。

总结如下:

客户端使用linux 在发送消息的时候,在windows7上面显示的信息是正确的,而windows 客户端显示的信息是在linux客户端上面是一个字符一个字符显示的.这个觉得跟windows7 使用的winsock有关?这个待验证

此文章为转载!

转载于:https://www.cnblogs.com/L-O-N/p/5471976.html

通过python 构建一个简单的聊天服务器相关推荐

  1. python推荐系统-利用python构建一个简单的推荐系统

    摘要: 快利用python构建一个属于你自己的推荐系统吧,手把手教学,够简单够酷炫. 本文将利用python构建一个简单的推荐系统,在此之前读者需要对pandas和numpy等数据分析包有所了解. 什 ...

  2. 基于python的系统构建_利用python构建一个简单的推荐系统

    摘要: 快利用python构建一个属于你自己的推荐系统吧,手把手教学,够简单够酷炫. 本文将利用python构建一个简单的推荐系统,在此之前读者需要对pandas和numpy等数据分析包有所了解. 什 ...

  3. python推荐_利用Python构建一个简单的推荐系统

    原标题:利用Python构建一个简单的推荐系统 摘要:快利用python构建一个属于你自己的推荐系统吧,手把手教学,够简单够酷炫.在此之前读者需要对pandas和numpy等数据分析包有所了解. 什么 ...

  4. 用python写一个简单的web服务器

    人生苦短,我用python 简洁高效,这才是理想的语言啊 分享一点python的学习经验-----如何用python写一个简单的web服务器 首先,我们需要简单地了解一下网络通信协议,这里用白话介绍一 ...

  5. python实现一个简单的http服务器

    需求:用python实现一个简单的http服务器 网页源码文件:https://download.csdn.net/download/d1240673769/46963534 该文件为html文件,如 ...

  6. python开发一个简单的聊天室

    使用python的twisted框架编写一个简单的聊天室 下面是基本架构 基本架构图 -- coding:utf-8 -- from twisted.internet.protocol import ...

  7. Actix-Web构建一个简单的HTTP服务器

    Actix-Web框架是目前性能上数一数二的rust的web框架,它的性能远超spring,nestJS, gin等目前流行的框架. 仅仅是返回hello,wold,我发现actix-web的性能就已 ...

  8. 用python做一个简单的http服务器。把huya的直播地址用python解出。解后在浏览器中调用openffplayer。

    接前面的工作 .这里主要在做一个简单的简单的http服务器.其实这个http是网上抄别人的. 主要文件有三个. 1,server.py 很简单的处理socket,还有处理httphead的线程.是一个 ...

  9. python构建一个简单的备份脚本

    编写思路: 1.建立一个空的列表,把需要备份的数据写入到列表,方便后面调用. 2.建立备份存放的目录. 3.调用os模块从列表里面读取数据,然后调用tar 命令进行备份. #!/usr/bin/pyt ...

最新文章

  1. FPGA基础知识极简教程(5)什么是锁存器以及如何在FPGA开发中避免生成锁存器?
  2. python是什么系统_最齐全、最系统的python教程
  3. java线程方法_Java线程的三种方式
  4. 作为阿里的面试官,我有话想说
  5. 深度学习框架再次升级,它们都有什么优点?
  6. 转 Procrastination
  7. 交换机putty怎么调试_弱电工程视频监控系统设计、安装、调试、维护全过程讲解...
  8. Oracle 行转列pivot 、列转行unpivot 的Sql语句总结
  9. 单点登录 cas 设置回调地址_单点登录终极方案之 CAS 应用及原理
  10. win11 鼠标样式修改(大小和颜色)
  11. 软件测试影响最深的bug,软件测试面试题-那些让我印象深刻的bug
  12. 数字信号处理声音降噪实验
  13. 为什么域名能够访问网站,而直接使用IP不可以
  14. 2020科目一考试口诀_2020年驾考科目一考试技巧与口诀
  15. Ubuntu下面scroll lock无法使用的解决方法
  16. Spring Boot系列——日志配置
  17. 英语六级高频词汇速记 + 2018-12-1听力 Day03
  18. pytorch操作基礎(二)——基礎
  19. python人狗大战游戏_day23 python学习 类 人狗大战
  20. 联想520r服务器装系统,联想Miix520本地模式重装win7系统教程

热门文章

  1. 微信小程序-注册成为小程序开发者
  2. events(事件触发器)
  3. SAP PS 第7节 物资采购类别、wbs bom及第三方采购
  4. Python爬取数据分析
  5. 极客云上使用anaconda配置python2.7+tensorflow1.8
  6. iOS开发-单元测试
  7. 如何在javascript中发出http请求?
  8. Java反射使用的Field类介绍
  9. 产品部和业务部门的利益之争
  10. p16panda合并concat