通过python 构建一个简单的聊天服务器
构建一个 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 方法
|
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 方法是这个聊天服务器的核心
|
辅助方法
在这个聊天服务器中有两个辅助方法,提供了接收新客户机连接和将消息广播到已连接的客户机上的功能。
当在到达连接队列中检测到一个新的客户机时,就会调用 accept_new_connection
方法(请参阅清单 18)。accept
方法用来接收这个连接,它会返回一个新的 socket
对象,以及远程地址信息。我们会立即将这个新的 socket 加入到 descriptors
列表中,然后向这个新的客户机输出一条消息欢迎它加入聊天。我创建了一个字符串来表示这个客户机已经连接了,使用 broadcast_string
方法来成组地广播这条消息(请参阅清单 19)。
注意,除了要广播的字符串之外,还要传递一个 socket 对象。原因是我们希望有选择地忽略一些 socket,从而只接收特定的消息。例如,当一个客户机向一个组中发送一条消息时,这条消息应该发送给这个组中除了自己之外的所有人。当我们生成状态消息来说明有一个新的客户机正在加入该组时,这条消息也不应该发送给这个新客户机,而是应该发送给其他所有人。这种任务是在 broadcast_string
中使用 omit_sock
参数实现的。这个方法会遍历 descriptors
列表,并将这个字符串发送给那些不是服务器 socket 且不是 omit_sock
的 socket。
清单 18. 在聊天服务器上接收一个新客户机连接
|
清单 19. 将一条消息在聊天组中广播
|
实例化一个新的 ChatServer
现在您已经看到了 Python 聊天服务器(这只使用了不到 50 行的代码),现在让我们看一下如何在 Python 中实例化一个新的聊天服务器。
我们通过创建一个新的 ChatServer
对象来启动一个服务器(传递要使用的端口号),然后调用 run
方法来启动服务器并允许接收所有到达的连接:
清单 20. 实例化一个新的聊天服务器
|
现在,这个服务器已经在运行了,您可以从一个或多个客户机连接到这个服务器上。也可以将几个方法串接在一起来简化这个过程(如果需要简化的话):
清单 21. 串接几个方法
|
这可以实现相同的结果。下面我们将展示 ChatServer
类的用法。
展示 ChatServer
下面就是 ChatServer
的用法。我们将展示 ChatServer
的输出结果(请参阅清单 22 )以及两个客户机之间的对话(请参阅清单 23 和 清单 24)。用户输入的文本以黑体形式表示。
清单 22. ChatServer 的输出
|
清单 23. 聊天客户机 #1 的输出
|
清单 24. 聊天客户机 #2 的输出
|
正如您在清单 22 中看到的那样,所有客户机之间的对话都会显示到 stdout 上,包括客户机的连接和断开消息。
总结如下:
客户端使用linux 在发送消息的时候,在windows7上面显示的信息是正确的,而windows 客户端显示的信息是在linux客户端上面是一个字符一个字符显示的.这个觉得跟windows7 使用的winsock有关?这个待验证
此文章为转载!
通过python 构建一个简单的聊天服务器的更多相关文章
- 使用纯php构建一个简单的PHP服务器
使用原生PHP构建一个简单的PHPWeb服务器 1.目录机构 webserver --src -- Response.php -- Server.php -- Request.php -- vendo ...
- 基于python创建一个简单的HTTP-WEB服务器
背景 大多数情况下主机资源只有开发和测试相关人员可以登录直接操作,且有些特定情况"答辩.演示.远程"等这些场景下是无法直接登录主机的.web是所有终端用户都可以访问了,解决了人员权 ...
- 用python实现一个简单的聊天功能,tcp,udp,socketserver版本
基于tcp协议版本 服务器端 import socket server = socket.socket() server.bind(('127.0.0.1', 8001)) server.listen ...
- 用Java构建一个简单的WebSocket聊天室
前言 首先对于一个简单的聊天室,大家应该都有一定的概念了,这里我们省略用户模块的讲解,而是单纯的先说说聊天室的几个功能:自我对话.好友交流.群聊.离线消息等. 今天我们要做的demo就能帮我们做到这一 ...
- 构建一个简单的 Google Dialogflow 聊天机器人【上】
概述 本教程将向您展示如何构建一个简单的Dialogflow聊天机器人,引导您完成Dialogflow的最重要功能.您将学习如何: 创建Dialogflow帐户和第一个Dialogflow聊天机器人, ...
- python练习四—简单的聊天软件
python最强大的是什么?库支持!!有了强大的库支持,一个简单的聊天软件实现就更简单了,本项目思路如下 # 项目思路 1. 服务器的工作 * 初始化服务器 * 新建一个聊天房间 * 维护一个已链接用 ...
- Python-黑客-004 用Python构建一个SSH僵尸网络-02 手动与SSH交互
用Python构建一个SSH僵尸网络-02 手动与SSH交互 - 登录SSH服务器端的 root 用户 我的电脑(攻击者)的系统:Ubuntu14.04 : 用户名: aobosir@ubuntu:~ ...
- Django入门第一步:构建一个简单的Django项目
Django入门第一步:构建一个简单的Django项目 1.简介 Django是一个功能完备的Python Web框架,可用于构建复杂的Web应用程序.在本文中,将通过示例跳入并学习Django.您将 ...
- 用Python写一个简单的Web框架
一.概述 二.从demo_app开始 三.WSGI中的application 四.区分URL 五.重构 1.正则匹配URL 2.DRY 3.抽象出框架 六.参考 一.概述 在Python中,WSGI( ...
随机推荐
- leetcode菜鸡斗智斗勇系列(8)--- Find N Unique Integers Sum up to Zero
1.原题: https://leetcode.com/problems/find-n-unique-integers-sum-up-to-zero/ Given an integer n, retur ...
- acm数论之旅---扩展欧几里得算法
度娘百科说: 首先, ax+by = gcd(a, b) 这个公式肯定有解 (( •̀∀•́ )她说根据数论中的相关定理可以证明,反正我信了) 所以 ax+by = gcd(a, b) * k 也肯定 ...
- DVWA实验之Brute Force(暴力破解)- Medium
DVWA实验之Brute Force(暴力破解)- Medium 有关DVWA环境搭建的教程请参考: https://www.cnblogs.com/0yst3r-2046/p/10928380. ...
- Bugku-CTF社工篇之密码
- 兔子与兔子(字符串hash)
传送门 很久很久以前,森林里住着一群兔子. 有一天,兔子们想要研究自己的 DNA 序列. 我们首先选取一个好长好长的 DNA 序列(小兔子是外星生物,DNA 序列可能包含 26 个小写英文字母). 然 ...
- 吴裕雄 python 神经网络——TensorFlow 花瓣分类与迁移学习(2)
import glob import os.path import numpy as np import tensorflow as tf from tensorflow.python.platfor ...
- MYSQL---外键 primary key 作用
https://www.cnblogs.com/x739400043/p/4732158.html 外键和级联 关于外键写的不错的网址:http://blog.csdn.net/lidaasky/ ...
- 监控Tomcat状态!(重点)
方法一:开发JAVA监控页面 [root@localhost ~]# mkdir /usr/local/tomcat8/webapps/memtest/[root@localhost ~]# cd / ...
- [理解] C++ 中的 源文件 和 头文件
我是学 C井 的, 现在在工作中主要使用的编程语言是 Java, 还记得当初在第一次接触到 Cpp 的时候, 听到的第一个概念就是 Cpp 的头文件和源文件, 当初理解了好久, 死活都弄不明白, 现在 ...
- Java入门笔记 03-面向对象(上)
介绍:Java是面向对象的程序设计语言,类是面向对象的重要内容,可以把类当成是一种自定义类型,可以使用类来定义变量,这种类型的变量统称为引用变量.也就是说,所有类都是引用类型.Java也支持面向对象的 ...