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基本的通信不断扩展其功能,实现一些简易的网络工具。近期感觉网安就业困难,以后可能还会更新一些大数据相关的内容,敬请期待。如果读者有什么问题也欢迎评论区指出,知无不言。总结不易,还请读者多多点赞关注支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/752582.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

供电系统分类详解

一、供电系统分类 电力供电系统一般有5种供电模式,常用的有:IT系统,TT系统,TN系统,其中TN系统又可以分为TN-C,TN-S,TN-C-S。 1、TN-C系统(三相四线制) 优点: 该系统中…

Hadoop大数据应用:NFS网关 连接 HDFS集群

目录 一、实验 1.环境 2.NFS网关 连接 HDFS集群 3. NFS客户端挂载HDFS文件系统 二、问题 1.关闭服务报错 2.rsync 同步报错 3. mount挂载有哪些参数 一、实验 1.环境 (1)主机 表1 主机 主机架构软件版本IP备注hadoop NameNode (…

【Mysql基础】查询01-去重、连接字符、模糊查询、通配符、检索表的结构信息

这里写目录标题 1 去重 distinct2 连接字符 concat(str1,str2,...)3 模糊查询3.1 like 包含3.2 通配符3.3 between and3.4 in3.5 is null 4 安全等于 <>5 检索表的结构信息 desc6 课后练习 1 去重 distinct 使用 DISTINCT 关键字&#xff0c;可以从结果集中去除重复的行…

Mac屏幕录制编辑软件

以下是一些Mac平台上受到推荐和好评的屏幕录制编辑软件&#xff1a; OBS Studio&#xff08;免费且开源&#xff09;&#xff1a; OBS 是一款功能强大的免费屏幕录制工具&#xff0c;不仅限于游戏直播&#xff0c;也适用于各种屏幕录制需求。它允许用户捕获屏幕、摄像头、音频&…

用c++实现装箱问题、数字回转方阵

3.4.1 装箱问题 【问题】有一个工厂制造的产品形状都是长方体&#xff0c;一共有6种型号,每种型号长方体的长和宽分别是11、22、33、44、55、66,高都是h。这些产品使用统一规格的箱子进行包装&#xff0c;箱子的长、宽和高分别是6、6和h。对于每个订单工厂希望用最少的箱子进行…

【蓝屏分析】WHEA_UNCORRECTABLE_ERROR 问题分析与解决

背景信息 电脑名字电脑类型厂商使用时间magicbook14 2020款 R5 4500U笔记本电脑荣耀HONOR3年9个月 内存CPUGPU硬盘焊死在主板上焊死在主板上集显PCIe 4.0 NVMe M.2 固态 软硬件错误源确定 电脑莫名频繁随机蓝屏&#xff0c;由于在软件环境上无迹可寻推测是硬件问题 蓝屏画面…

Windows系统部署hMailServer邮件服务结合内网穿透实现公网收发邮件

文章目录 前言1. 安装hMailServer2. 设置hMailServer3. 客户端安装添加账号4. 测试发送邮件5. 安装cpolar6. 创建公网地址7. 测试远程发送邮件8. 固定连接公网地址9. 测试固定远程地址发送邮件 前言 hMailServer 是一个邮件服务器,通过它我们可以搭建自己的邮件服务,通过cpola…

运动想象 (MI) 迁移学习系列 (9) : 数据对齐(EA)

运动想象迁移学习系列:数据对齐&#xff08;EA&#xff09; 0. 引言1. 迁移学习算法流程2. 欧式对齐算法流程3. 与RA算法进行对比4. 实验结果对比5. 总结欢迎来稿 论文地址&#xff1a;https://ieeexplore.ieee.org/abstract/document/8701679 论文题目&#xff1a;Transfer Le…

数据结构:链式二叉树

对于二叉树而言,如果不是完全二叉树,就不再适合用数组存储了 二叉树结构 typedef struct BinTreeNode {int val;struct BinTreeNode* left;struct BinTreeNode* right; }BTNode; 二叉树的遍历 顺序 访问顺序(n NULL) 1.前序 根,左子树…

软考81-上午题-【面向对象技术3-设计模式】-行为型设计模式01

一、行为型设计模式一览 二、责任链模式 2-1、意图 使多个对象都有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链&#xff0c;并沿着这条链传递该请求&#xff0c;直到有一个对象处理它为止。 1-2、结构 1-3、代码实现 1-4、适…

3D产品配置器能为企业的客户带来什么好处?

3D产品配置器能够为企业的客户带来多重好处&#xff0c;提升他们的整体购物体验和满意度。 主要优势分析&#xff1a; 1、 提升购物体验&#xff1a;3D产品配置器通过提供交互式的3D可视化体验&#xff0c;使客户能够从不同角度查看和理解产品&#xff0c;从而提升他们的购物体…

银行信息系统应用架构导论-引用

一级目录二级目录金融标准和参考文档一、银行企业级应用系统架构规划企业级应用系统架构规划《金融科技发展规划&#xff08;2022-2025年&#xff09;&#xff08;2022年1月中国人民银行印发&#xff09;》 《关于银行业保险业数字化转型的指导意见&#xff08;2022年1月中国银…

Python图像处理【23】分布式图像处理

分布式图像处理 0. 前言1. Dask 简介2. 使用 Dask 进行分布式图像处理2.1 将 RGB 图像块转换为灰度图像块2.2 使用分布式 Sobel 滤波器检测图像边缘 小结系列链接 0. 前言 Python 已逐渐成为数据分析/处理领域中的主要语言&#xff0c;这得益于 Python 丰富的第三方库&#xf…

【对顶队列】【中位数贪心】【前缀和】100227. 拾起 K 个 1 需要的最少行动次数

本文涉及知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 对顶队列&#xff08;栈&#xff09; 分类讨论 LeetCode100227. 拾起 K 个 1 需要的最少行动次数 给你一个下标从 0 开始的二进制数组 nums&#xff0c;其长度为 n &#x…

python redis中blpop和lpop的区别

python redis中lpop()方法是获取并删除左边第一个对象。 def lpop(self,name: str,count: Optional[int] None,) -> Union[Awaitable[Union[str, List, None]], Union[str, List, None]]:"""Removes and returns the first elements of the list name.By de…

VR历史建筑漫游介绍|虚拟现实体验店加盟|VR设备购买

VR历史建筑漫游是一种利用虚拟现实技术&#xff0c;让用户可以身临其境地参观和探索历史建筑的体验。通过VR头显和相关设备&#xff0c;用户可以在虚拟环境中自由移动和互动&#xff0c;感受历史建筑的真实氛围和文化内涵。 在VR历史建筑漫游中&#xff0c;您可以选择不同的历史…

为什么手机和电视ip地址不一样

在数字化时代&#xff0c;我们每天都会与各种电子设备打交道&#xff0c;其中最常见的就是手机和电视。当我们连接到互联网时&#xff0c;这些设备都会被分配一个独特的IP地址&#xff0c;用于在网络上进行标识和通信。然而&#xff0c;您可能已经注意到&#xff0c;即使手机和…

基于java+springboot+vue实现的高校教师工作量管理系统(文末源码+Lw+ppt)23-451

摘 要 高校教师工作量管理系统采用B/S架构&#xff0c;数据库是MySQL。网站的搭建与开发采用了先进的java进行编写&#xff0c;使用了springboot框架。该系统从两个对象&#xff1a;由管理员和教师来对系统进行设计构建。主要功能包括&#xff1a;个人信息修改&#xff0c;对…

vue2点击左侧的树节点(el-tree)定位到对应右侧树形表格(el-table)的位置,树形表格懒加载

左侧树代码 <el-tree :data"treeData" node-key"id" default-expand-all"" //节点默认全部展开:expand-on-click-node"false" //是否在点击节点的时候展开或者收缩节点:props"defaultProps" node-click"handleNodeC…

《LeetCode热题100》笔记题解思路技巧优化_Part_2

《LeetCode热题100》笔记&题解&思路&技巧&优化_Part_2 &#x1f60d;&#x1f60d;&#x1f60d; 相知&#x1f64c;&#x1f64c;&#x1f64c; 相识&#x1f622;&#x1f622;&#x1f622; 开始刷题普通数组&#x1f7e1;1. 最大子数组和&#x1f7e1;2. 合…