python实现socket+threading处理多连接的方法
作者:狡猾的皮球 发布时间:2021-12-16 17:54:32
标签:python,socket,threading,多连接
一.运行效果
先说两句,之前我在网上找的相关文章标题上写的是处理多连接,尼玛,全是假的。网上那些,根本不能异步处理多连接,不能主动给客户端发消息。
在服务端控制台输入1,查看在线人数。
给指定客户端发送消息。
二.开发思路
以下说的是服务端开发思路,客户端比较简单就不说了。
首先,需要明白的是socket的accept和recv这两个方法是阻塞线程的。这就意味着我们需要新开线程来处理这两个方法。
具体的程序流程大概是这样的:
1.新开一个线程用于接收新的连接(socket.accept())
2.当有新的连接时,再新开一个线程,用于接收这个连接的消息(socket.recv())
3.主线程做为控制台,接收用户的输入,进行其他操作
也就是说,服务端需要为每一个连接创建一个线程。
三.服务端代码
全局部分的代码:
import socket # 导入 socket 模块
from threading import Thread
ADDRESS = ('127.0.0.1', 8712) # 绑定地址
g_socket_server = None # 负责监听的socket
g_conn_pool = [] # 连接池
其中,g_conn_pool是用来存放每一个客户端socket的。
初始化服务端:
def init():
"""
初始化服务端
"""
global g_socket_server
g_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建 socket 对象
g_socket_server.bind(ADDRESS)
g_socket_server.listen(5) # 最大等待数(有很多人理解为最大连接数,其实是错误的)
print("服务端已启动,等待客户端连接...")
socket.listen()的参数意义不要理解错了哦~
接收客户端连接和处理客户端消息:
def accept_client():
"""
接收新连接
"""
while True:
client, _ = g_socket_server.accept() # 阻塞,等待客户端连接
# 加入连接池
g_conn_pool.append(client)
# 给每个客户端创建一个独立的线程进行管理
thread = Thread(target=message_handle, args=(client,))
# 设置成守护线程
thread.setDaemon(True)
thread.start()
def message_handle(client):
"""
消息处理
"""
client.sendall("连接服务器成功!".encode(encoding='utf8'))
while True:
bytes = client.recv(1024)
print("客户端消息:", bytes.decode(encoding='utf8'))
if len(bytes) == 0:
client.close()
# 删除连接
g_conn_pool.remove(client)
print("有一个客户端下线了。")
break
设置成守护线程的目的是为了防止主线程退出之后,程序进程不退出。
消息处理这一块,如果接收到一个长度为0的数据包,那么说明客户端掉线了。实际开发中,我们一般采用心跳包机制判断客户端是否在线。
最后,调用这些方法,让服务端启动:
if __name__ == '__main__':
init()
# 新开一个线程,用于接收新连接
thread = Thread(target=accept_client)
thread.setDaemon(True)
thread.start()
# 主线程逻辑
while True:
cmd = input("""--------------------------
输入1:查看当前在线人数
输入2:给指定客户端发送消息
输入3:关闭服务端
""")
if cmd == '1':
print("--------------------------")
print("当前在线人数:", len(g_conn_pool))
elif cmd == '2':
print("--------------------------")
index, msg = input("请输入“索引,消息”的形式:").split(",")
g_conn_pool[int(index)].sendall(msg.encode(encoding='utf8'))
elif cmd == '3':
exit()
如果对流程不清楚的话,可以再回到上面,看看文章的第二部分。
四.客户端代码
客户端这部分设计的很简单。
import socket # 导入 socket 模块
s = socket.socket() # 创建 socket 对象
s.connect(('127.0.0.1', 8712))
print(s.recv(1024).decode(encoding='utf8'))
s.send("连接了".encode('utf8'))
print(s.recv(1024).decode(encoding='utf8'))
input("")
最后的input是为了阻塞线程,防止程序接收到消息之后就退出了。
来源:https://blog.csdn.net/qq_39687901/article/details/81531101


猜你喜欢
- 一、简介pd.concat()函数可以沿着指定的轴将多个dataframe或者series拼接到一起。基本语法:pd.concat( obj
- 本文实例讲述了django框架模板语言使用方法。分享给大家供大家参考,具体如下:模板功能作用:生成html界面内容,模版致力于界面如何显示,
- 功能性的文章直接用几个最简单的实现表达:xlsxwriter库的核心就是其Workbook对象。创建一个指定名字的xlsx文件:import
- 给定一个文件夹,使用Python检查给定文件夹下有无文件重复,若存在重复则删除主要涉及的知识点有:os模块综合应用glob模块综合应用利用f
- JetBrainsMono 是 JetBrains 公司开发的一款开源字体,可免费商用。正如其名字带的Mono,即Monospaced Fo
- Keyboard Scan Codes (Numerical Order)Keyboard Scan Codes (Numeri
- 今天来说一下,有些刚刚接触python的朋友,在使用pip install安装python 第三方库的过程中会出现网速很慢,或者是安装下载到
- 菜鸟笔记首先读取的txt文件如下:AAAAF110 0003E818 0003E1FC 0003E770 0003FFFC 90AAAAF1
- 场景一:A网站全站均为UTF-8编码,B网站全站为GB2312编码。A网站提供一段JS代码供B网站调用,该代码会动态生成一个FORM表单,以
- 在本文中,我想向您介绍如何在Django中使用聚合,聚合的含义是“内容相关项的集合,以便它们可以显示或链接到”。在Django中,我们使用的
- 本文实例讲述了Go语言实现socket的方法。分享给大家供大家参考。具体分析如下:用golang不用他的net包还有什么意义,这里提供一个测
- 前言小伙伴a,b,c围着吃火锅,当菜上齐了,请客的主人说:开吃!,于是小伙伴一起动筷子,这种场景如何实现Event(事件)Event(事件)
- 本文实例为大家分享了python dlib人脸识别的具体代码,供大家参考,具体内容如下import matplotlib.pyplot as
- 1、requests 的常见用法requests 除了 url 之外,还有 params, data 和 files 三个参数,用于和服务器
- 一、触发器的介绍触发器是与表有关的数据库对象,指在insert/update/delete 之前或之后,触发并执行触发器中定义的SQL语句集
- /** * 得到XML文件属性的集合对象 * @param x
- bytes 和 bytearraybytes 和 bytearray 都是二进制世界的成员,用二进制的方式去理解才能看清他的本质。理解byt
- 前言21世纪是信息的世纪,综合国力的竞争在很大程度上是信息的竞争,更是信息利用率的竞争。近年来,随着“数字地球”和“数字国土”战略的提出和实
- 具体代码如下所示:#coding=utf8from urllib import requestimport reimport urllib,
- 本文实例讲述了MySQL查询条件常见用法。分享给大家供大家参考,具体如下:条件使用where子句对表中的数据筛选,结果为true的行会出现在