python网络编程:通过socket实现TCP客户端和服务端
目录
写在开头
socket服务端(基础)
socket客户端(基础)
服务端实现(可连接多个客户端)
客户端实现
数据收发效果
写在开头
近期可能会用python实现一些网络安全工具,涉及到许多关于网络的知识,逃不过的就是最基本的socket。本文将介绍如何通过python自带的socket库实现TCP客户端和服务端,实现多个客户端与一个服务端的消息收发,这是网络编程的基础。尽管python有许多第三方库可以创建网络客户端和服务端,但其核心都是socket模块,socket模块提供了许多有关网络连接的接口,可以干很多事情,后续我们还可能基于本文的案例慢慢继续开发,实现一些主机扫描、数据包注入等工具。

socket(套接字)是进程之间进行网络通信的媒介,通信时分为服务端和客户端,可见下图(图来自黑马程序员的python课件)。
socket服务端:被动等待其他进程(客户端)的连接,可以同时连接多个客户端,与之通信实现消息的收发。
socket客户端:主动连接服务端,与服务端通信。

下面我们先实现一个基础的服务端和客户端,实现一个客户端与一个服务端之间的通信。
socket服务端(基础)
首先引入socket模块,并创建socket服务端对象socket_server,此时该对象还无法确定是客户端/服务端,作为服务端,应当绑定一个服务端的主机和端口,这里就以本地"localhost",端口8888为例,通过.bind方法传入元组。
import socket
# 创建socket对象
socket_server = socket.socket()
# 绑定ip和端口,表明是服务端
socket_server.bind(("localhost", 8888))
接下来通过listen方法让服务器开始监听,传入一个int整数,表示最大连接数。此处我们实现最基础的情况传入1,仅允许一个客户端连接该服务端。接下来通过accept方法等待客户端的连接,在此之前我们可以通过print打印提示“正在等待客户端连接”。accept方法是一个阻塞是的方法,如果没有客户端连接,程序将一直在这里等待连接。.accept()方法返回一个二元元组(conn, client_addr),conn表示客户端和服务端的连接对象,client_addr = (client_host, client_port),我们用两个变量conn和address分别接收:
# listen方法内接受一个整数传参数,表示接受的连接数量,可不填
socket_server.listen(1)
# 等待客户端连接,accept方法返回二元元组(连接对象, 客户端地址信息)
# accept()方法是阻塞式的方法,如果没有客户端连接,会一直等待,不往下执行
print(f"服务端已开始监听,正在等待客户端连接...")
conn, address = socket_server.accept()
print(f"接收到了客户端的连接,客户端的信息:{address}}")
下面就可以实现数据的收发了,数据的收发基于本次服务端与客户端的连接对象conn,而非socket对象socket_server。这里假设客户端先发来消息,服务端先接收客户端发来的消息,再给客户端发送消息。接收消息使用recv方法,该方法也是阻塞式,只要没有接收到数据就会一直等待。其中的参数是缓冲区大小,通常填1024即可,recv接收到的消息(返回值)是字节流bytes对象,因此还需要通过decode方法解码为字符串:
data: str = conn.recv(1024).decode("UTF-8")
接收完成后,服务端通过send方法发送消息到客户端,同样,也需要将字符串编码为字节流的形式:
msg = input("请输入你要回复客户端的消息:")conn.send(msg.encode("UTF-8")) # encode将字符串编码为字节数组对象
完善一下代码,服务端实现持续的消息接收和发送,直到服务端输入"exit"退出,关闭服务端:
while True:# 接收消息data: str = conn.recv(1024).decode("UTF-8")print(f"客户端发来的消息是:{data}")# 回复消息msg = input("请输入你要回复客户端的消息:")if msg == 'exit':breakconn.send(msg.encode("UTF-8")) # encode将字符串编码为字节数组对象
最后关闭此次连接即可,并关闭服务端。
conn.close()
socket_server.close()
完整的服务端socket_server.py代码如下:
import socketsocket_server = socket.socket()
socket_server.bind(("localhost", 8888))
# 监听端口
socket_server.listen(1)
# 等待客户端连接,accept方法返回二元元组(连接对象, 客户端地址信息)
print(f"服务端已开始监听,正在等待客户端连接...")
conn, address = socket_server.accept()
print(f"接收到了客户端的连接,客户端的信息:{address}}")# 接受客户端信息,使用客户端和服务端的本次连接对象,而非socket_server
while True:# 接收消息data: str = conn.recv(1024).decode("UTF-8")print(f"客户端发来的消息是:{data}")# 回复消息msg = input("请输入你要回复客户端的消息:")if msg == 'exit':breakconn.send(msg.encode("UTF-8")) # encode将字符串编码为字节数组对象# 关闭连接
conn.close()
socket_server.close()
写完了不要着急运行,我们搞定客户端再一起试试。
socket客户端(基础)
客户端的代码和服务端差不多,只不过客户端是主动连接服务器,因此需要.connect方法连接服务器的host和端口,传入元组(服务端主机, 服务端端口号)即可,此处我们传入("localhost", 8888):
import socket
# 创建socket对象
socket_client = socket.socket()
# 连接到服务器
socket_client.connect(("localhost", 8888))
接下来实现数据的发送和接收,此处客户端先发送消息给服务端,再接收服务端回复的消息。同样的方法,send方法发送,recv方法接收,注意Bytes字节流和字符串的转换即可:
while True:send_msg = input("请输入要发送给服务端的消息:")if send_msg == "exit":break# 发送消息到服务端socket_client.send(send_msg.encode("UTF-8"))# 接收服务端的消息recv_data = socket_client.recv(1024).decode("UTF-8") # 1024是缓冲区大小,一般就填1024, recv是阻塞式print(f"服务端回复的消息是:{recv_data}")
类似,最后关闭连接:
# 关闭连接
socket_client.close()
完整的客户端代码socket_client.py如下:
import socket
# 创建socket对象
socket_client = socket.socket()
# 连接到服务器
socket_client.connect(("localhost", 8888))while True:send_msg = input("请输入要发送给服务端的消息:")if send_msg == "exit":break# 发送消息socket_client.send(send_msg.encode("UTF-8"))# 接受消息recv_data = socket_client.recv(1024).decode("UTF-8") # 1024是缓冲区大小,一般就填1024, recv是阻塞式print(f"服务端回复的消息是:{recv_data}")# 关闭连接
socket_client.close()
代码完成之后,我们先运行服务端代码socket_server.py,即可实现绑定服务器端口并等待客户端连接:

然后开启客户端,运行socket_client.py即可建立连接 :

此时回到刚才的服务端界面,可以发现出现了提示:建立了连接,此次连接的客户端主机是本机127.0.0.1,端口是2133:
在客户端输入消息,即可实现客户端到服务端的消息传送,同理服务端也可以发送数据到客户端:


任意一方输入exit即退出,另一方再发消息,由于连接已经关闭,会出现异常:


这样我们就实现了客户端与服务端的通信,但此时只能有一个客户端连接到服务端,如果想实现多个客户端,就需要修改服务端listen()的参数,允许更多的客户端连接,下面进行讲解。
服务端实现(可连接多个客户端)
这里先直接给出完整的代码server.py:
import socket
import threadingdef create_server_socket(host, port):socket_server = socket.socket()socket_server.bind((host, port))socket_server.listen(5)print(f"服务端已启动,地址{host},端口{port}")print(f"正在等待客户端连接...")# 开启多线程,收发来自多个客户端的数据num = 0 # 标记客户端的编号while True:num += 1conn, address = socket_server.accept()print(f"服务端已接受到客户端 {num}号 的连接请求,客户端信息:{address}")client_handler = threading.Thread(target=handle_client, args=(conn, address, num))client_handler.start()# 处理收发数据
def handle_client(conn, address, num):while True:# 接收客户端发来的数据data_from_client: str = conn.recv(1024).decode("UTF-8")print(f"客户端 {num}号:{address}发来的消息是:{data_from_client}")# 发送消息到客户端msg = input(f"请输入你要回复客户端 {num}号:{address}的消息:")if msg == 'exit':breakconn.send(msg.encode("UTF-8")) # encode将字符串编码为字节数组对象conn.close()if __name__ == '__main__':server_host = input("请输入服务端Host:")server_port = int(input("请输入服务端port:"))create_server_socket(server_host, server_port)
其实也没有特别多的变化,通过函数进行了封装,然后修改listen方法,传一个大于1的整数,表示允许更多的客户端连接,此处设置的最大连接数为5。将数据收发的过程封装在函数handle_client中,额外设置了参数num表示这是第几个连接到该服务端的客户端。
当一个客户端成功建立连接的时候(即运行完成conn, address = socket_server.accept()之时),将接收到的客户端socket对象保存在conn变量,远程连接信息(客户端host, 客户端port)保存在address变量,并启动线程指向handle_client函数,传入连接对象conn,连接信息address和客户端号num。创建好之后,启动该线程。于此同时,服务端create_server_socket中的while True循环也已经准备好处理下一个潜在的客户端连接。
客户端实现
客户端和刚才的其实可以没啥区别,这里重新用函数封装为client1.py好了:
import socketdef create_client(host, port):socket_client = socket.socket()socket_client.connect((host, port))# 发送、接受数据while True:msg = input(f"请输入客户端1发送给服务端{host}:{port}的数据:")if msg == "exit":break# 发送数据到服务端socket_client.send(msg.encode("UTF-8"))# 接收服务端的数据data_from_server = socket_client.recv(1024).decode("UTF-8")print(f"客户端接收到服务端的消息:{data_from_server}")socket_client.close()if __name__ == '__main__':server_host = input("请输入想要连接的服务端Host:")server_port = int(input("请输入想要连接的服务端port:"))create_client(server_host, server_port)
由于要实现多个客户端的连接,我们可以创建另外一个文件client2.py,代码和client1一样。这里我就用刚才的socket_client.py做示范好了。
数据收发效果
首先运行服务端代码server.py。输入服务端的host(本地localhost)和port(8888),此时服务端就进入了等待客户端连接的状态:

再运行客户端代码client1.py和socket_client.py 输入服务端的host和端口,即可建立连接:


服务端显示连接建立成功,两个连接均已建立:

然后两个连接即可各自实现服务端与客户端的数据收发,注意都是客户端先发送消息,服务端先接收消息。客户端1号client.py如下:

客户端2号socket_server.py运行交互过程如下:

服务端server.py的运行交互过程如下:
任何一端输入exit即可退出,对应的客户端和服务端建立的连接会断开(其他的连接依旧正常通信),比如这里服务端断开与client1的连接,与客户端2 socket_client的通信不受影响:

client1客户端1由于服务端已经端口,异常退出了:
客户端2不受影响:

到这里就实现了多个客户端与服务端的消息传送。当然本文没有考虑如何处理阻塞、如何进行异常处理等细枝末节。后续可能会继续改进,并基于socket基本的通信不断扩展其功能,实现一些简易的网络工具。近期感觉网安就业困难,以后可能还会更新一些大数据相关的内容,敬请期待。如果读者有什么问题也欢迎评论区指出,知无不言。总结不易,还请读者多多点赞关注支持。

相关文章:
python网络编程:通过socket实现TCP客户端和服务端
目录 写在开头 socket服务端(基础) socket客户端(基础) 服务端实现(可连接多个客户端) 客户端实现 数据收发效果 写在开头 近期可能会用python实现一些网络安全工具,涉及到许多关于网络…...
论文阅读——RSGPT
RSGPT: A Remote Sensing Vision Language Model and Benchmark 贡献:构建了一个高质量的遥感图像描述数据集(RSICap)和一个名为RSIEval的基准评估数据集,并在新创建的RSICap数据集上开发了基于微调InstructBLIP的遥感生成预训练…...
长连接技术
个人学习记录,欢迎指正 1.轮询 1.1 轮询的形式 短连接轮询 前端每隔一段时间向服务端发起一次Http请求来获取数据。 const shortPolling () > { const intervalHandler setInterval(() > {fetch(/xxx/yyy).then(response > response.json()).then(respo…...
供电系统分类详解
一、供电系统分类 电力供电系统一般有5种供电模式,常用的有:IT系统,TT系统,TN系统,其中TN系统又可以分为TN-C,TN-S,TN-C-S。 1、TN-C系统(三相四线制) 优点: 该系统中…...
基于centos7的k8s最新版v1.29.2安装教程
k8s概述 Kubernetes 是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快速增长的生态,其服务、支持和工具的使用范围相当广泛。 Kubernetes 这个名字源于希腊语&…...
【赠书第20期】AI绘画与修图实战:Photoshop+Firefly从入门到精通
文章目录 前言 1 入门篇:初识Photoshop与Firefly 2 进阶篇:掌握Photoshop与Firefly的核心技巧 3 实战篇:运用Photoshop与Firefly进行创作 4 精通篇:提升创作水平,拓展应用领域 5 结语 6 推荐图书 7 粉丝福利 前…...
如何在并行超算云上玩转PWmat③:使用Q-Flow提交计算的案例演示
3月的每周二下午14:00我们将会在并行直播间为大家持续带来线上讲座。前面两期我们分享了”PWmat特色功能和应用“以及“如何在并行超算云平台使用PWmat计算软件”主题讲座,回看视频和PPT已上传至B站”龙讯旷腾“账号内。 本周张持讲师将继续带着大家手把手上机教学…...
html5cssjs代码 017样式示例
html5&css&js代码 017样式示例 一、代码二、解释 这段HTML代码定义了一个网页的基本结构,包括头部、主体和尾部。在头部中,设置了网页标题、字符编码和样式。主体部分包含一个标题和一个表格,表格内分为两个单元格,左侧为…...
Vue.js动画
Vue.js动画 Vue.js动画是指在Vue组件中通过添加/移除CSS类或应用CSS过渡/动画效果来实现的视觉效果。这些动画可以帮助改善用户体验,使界面更加生动和吸引人。 Vue.js提供了两种类型的动画:过渡和动画。 过渡:过渡是在元素插入、更新或删除…...
信号与系统学习笔记——信号的分类
目录 一、确定与随机 二、连续与离散 三、周期与非周期 判断是否为周期函数 离散信号的周期 结论 四、能量与功率 定义 结论 五、因果与反因果 六、阶跃函数 定义 性质 七、冲激函数 定义 重要关系 作用 一、确定与随机 确定信号:可以确定时间函数…...
PyTorch深度学习实战(39)——小样本学习
PyTorch深度学习实战(39)——小样本学习 0. 前言1. 小样本学习简介2. 孪生网络2.1 模型分析2.2 数据集分析2.3 构建孪生网络 3. 原型网络3. 关系网络小结系列链接 0. 前言 小样本学习 (Few-shot Learning) 旨在解决在训练集中只有很少样本的情况下进行分…...
论文阅读——Vision Transformer with Deformable Attention
Vision Transformer with Deformable Attention 多头自注意力公式化为: 第l层transformer模块公式化为: 在Transformer模型中简单地实现DCN是一个non-trivial的问题。在DCN中,特征图上的每个元素都单独学习其偏移,其中HWC特征图上…...
AJAX概念和axios使用、URL、请求方法和数据提交、HTTP协议、接口、form-serialize插件
AJAX概念和axios使用 AJAX概念 AJAX就是使用XMLHttpRequest对象与服务器通信,它可以使用JSON、XML、HTML和text文本等格式发送和接收数据,AJAX最吸引人的就是它的异步特性,也就是说它可以在不重新刷新页面的情况下与服务器通信,…...
【R语言基础操作】
🍉CSDN小墨&晓末:https://blog.csdn.net/jd1813346972 个人介绍: 研一|统计学|干货分享 擅长Python、Matlab、R等主流编程软件 累计十余项国家级比赛奖项,参与研究经费10w、40w级横向 文…...
sqlite 常见命令 表结构
在 SQLite 中,将表结构保存为 SQL 具有一定的便捷性和重要性,原因如下 便捷性: 备份和恢复:将表结构保存为 SQL 可以方便地进行备份。如果需要还原或迁移数据库,只需执行保存的 SQL 脚本,就可以重新创建表…...
基于深度学习的车辆检测技术
基于深度学习的车辆检测技术是现代智能交通系统的重要组成部分,它利用计算机视觉和机器学习算法,特别是深度学习模型,来识别和定位图像或视频中的车辆。这项技术广泛应用于自动驾驶、交通监控、违章抓拍等多个领域。 深度学习车辆检测技术的…...
MyBatis 之三:配置文件详解和 Mapper 接口方式
配置文件 MyBatis 的配置文件是 XML 格式的,它定义了 MyBatis 运行时的核心行为和设置。默认的配置文件名称为 mybatis-config.xml,该文件用于配置数据库连接、事务管理器、数据源、类型别名、映射器(mapper 文件)以及其他全局属性…...
【PyTorch】基础学习:一文详细介绍 torch.load() 的用法和应用
【PyTorch】基础学习:一文详细介绍 torch.load() 的用法和应用 🌈 个人主页:高斯小哥 🔥 高质量专栏:Matplotlib之旅:零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程ὄ…...
事务、并发、锁机制的实现
配置全局事务 DATABASES {default: {ENGINE: django.db.backends.mysql,NAME: mydb,USER:root,PASSWORD:pass,HOST:127.0.0.1,PORT:3306,ATOMIC_REQUESTS: True, # 全局开启事务,绑定的是http请求响应整个过程# (non_atomic_requests可局部实现不让事务控制)} } …...
PC-DARTS: PARTIAL CHANNEL CONNECTIONS FOR MEMORY-EFFICIENT ARCHITECTURE SEARCH
PC-DARTS:用于内存高效架构搜索的部分通道连接 论文链接:https://arxiv.org/abs/1907.05737 项目链接:https://github.com/yuhuixu1993/PC-DARTS ABSTRACT 可微分体系结构搜索(DARTS)在寻找有效的网络体系结构方面提供了一种快速的解决方案…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
Python 高效图像帧提取与视频编码:实战指南
Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
数据结构第5章:树和二叉树完全指南(自整理详细图文笔记)
名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪) 原创笔记:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 上一篇:《数据结构第4章 数组和广义表》…...
聚六亚甲基单胍盐酸盐市场深度解析:现状、挑战与机遇
根据 QYResearch 发布的市场报告显示,全球市场规模预计在 2031 年达到 9848 万美元,2025 - 2031 年期间年复合增长率(CAGR)为 3.7%。在竞争格局上,市场集中度较高,2024 年全球前十强厂商占据约 74.0% 的市场…...
iOS 项目怎么构建稳定性保障机制?一次系统性防错经验分享(含 KeyMob 工具应用)
崩溃、内存飙升、后台任务未释放、页面卡顿、日志丢失——稳定性问题,不一定会立刻崩,但一旦积累,就是“上线后救不回来的代价”。 稳定性保障不是某个工具的功能,而是一套贯穿开发、测试、上线全流程的“观测分析防范”机制。 …...
