【python高级】342-TCP服务器开发流程

news2024/12/25 12:11:09

CS模式:客户端-服务端模式

TCP客户端开发流程介绍(五步)(C端)
1.创建客户端套接字对象
2.和服务端套接字建立连接
3.发送数据
4.接收数据
5.关闭客户端套接字
TCP服务端开发流程(七步)(S端)
1.创建服务端端套接字对象
2.绑定端口号
3.设置监听
4.等待接受客户端的连接请求
5.接收数据
6.发送数据
7.关闭套接字

TCP客户端程序开发

import socket

# 第一步:创建客户端套接字对象
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # socket.AF_INET表示IPV4,socket.SOCK_STREAM表示TCP协议

# 第二步:创建连接
tcp_client_socket.connect(("127.0.0.1", 8000))  # 参数是个元组

# 第三步:发送数据到服务器端
tcp_client_socket.send("hello".encode("utf-8"))  # 这里将字符串编码成二进制数据

# 第四步:接收服务器端返回的数据
recv_data = tcp_client_socket.recv(1024).decode("utf-8")  # 1024表示本次接收的最大字节数,decode解码
print(f"接收到的数据为:{recv_data}")  # 将二进制数据解码成字符串

# 第五步:关闭套接字对象
tcp_client_socket.close()

tip:发送和接受的都要是二进制数据,所以要用encode和decode方法将字符串转换成二进制数据

  • encode():将字符串转换成二进制数据
  • decode():将二进制数据转换成字符串

关于socket.AF_INET、socket.SOCK_STREAM常量的介绍:

  • socket.AF_INET(IPv4)
    • 这是 Python 中socket模块里的一个常量,AF_INET代表 Address Family(地址族)为INET,用于指定网络通信使用的地址族是 IPv4 地址族。
    • 当创建一个套接字(socket)时,通过指定AF_INET,告诉操作系统这个套接字将用于基于 IPv4 协议的网络通信。
  • socket.SOCK_STREAM(TCP)
    • 这是socket模块中的另一个常量,用于指定套接字的类型为流套接字。
      • 当和AF_INET一起使用创建套接字时(如前面代码示例中的socket.socket(socket.AF_INET, socket.SOCK_STREAM)),它表示创建的是一个基于 TCP(Transmission Control Protocol)协议的流套接字。TCP 是一种面向连接的、可靠的传输协议,SOCK_STREAM类型的套接字利用 TCP 协议提供的特性,如三次握手建立连接、数据的可靠传输(通过确认、重传等机制)、流量控制和拥塞控制等。
      • 这种类型的套接字适用于需要保证数据准确无误地传输的应用场景,比如 HTTP(超文本传输协议)用于网页浏览,SMTP(简单邮件传输协议)用于发送电子邮件等。它提供了一个字节流的接口,应用程序可以像读写文件一样通过这个套接字进行数据的发送和接收,而不必担心数据的丢失或损坏,因为 TCP 协议在底层会处理这些问题。

TCP服务端程序开发(重点)

开发的七步:
1.创建服务端套接字对象
2.绑定端口号
3.设置监听
4.等待接受客户端的连接请求:类似于input() → accept()阻塞
5.接收数据
6.发送数据
7.关闭套接字

服务器如何判断是哪个客户端连接:
通过accept()方法返回的套接字对象来区分不同的客户端

import socket

# 1.创建服务端套接字对象
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # socket.AF_INET表示IPV4,socket.SOCK_STREAM表示TCP协议

# 2.绑定端口号
tcp_server_socket.bind(("127.0.0.1", 8000))  # 如果是本机,可以不写ip地址

# 3.设置监听
tcp_server_socket.listen(128)  # 128表示最大连接数

# 4.等待接受客户端的连接请求
new_socket, ip_port = tcp_server_socket.accept()  # 阻塞状态,等待客户端连接
# tcp_server_socket对象主要用于接收客户端连接:绑定端口、设置监听、接收连接
# new_socket对象主要用于接收和发送数据
print(f"新连接的客户端地址为:{ip_port}")
print(f"新连接的客户端socket对象为:{new_socket}")

# ================================================
# 5.接收数据
recv_data = new_socket.recv(1024).decode("utf-8")  # 1024表示本次接收的最大字节数,decode解码	
print(f"接收到的数据为:{recv_data}")

# 6.发送数据
new_socket.send("信息已收到".encode("utf-8"))  # 将字符串编码成二进制数据

# 7.关闭新套接字对象(关闭后不能收发消息)和服务端套接字对象(不能接收新连接)
new_socket.close()
tcp_server_socket.close()

当客户端发送信息后,接收到的data是一个元组,下面是个栗子,元组有两个元素,第一个元素是套接字对象,第二个元素是客户端的地址(也是元组)

(
	<socket.socket fd=432, family=AddressFamily.AF_INET, ttype=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8000), raddr=('127.0.0.1', 60925)>, 
	('127.0.0.1', 60925)
)

注意事项:

  • 明确自己开发的到底是客户端还是服务端
    • 客户端:connect()、send()、recv()、close()
    • 服务端:socket()、bind()、listen()、accept()、recv()、send()、close()
  • 两个对象要分清楚
    • tcp_server_socket:主要用于接收客户端连接
      • 内部只有服务器本身的信息,可以绑定端口、设置监听、接收连接
    • new_socket:主要用于接收和发送数据
      • 内部既有客户端又有服务器端信息,可以接收和发送数据
      • 只能通过这个新套接字来收发数据

服务器端面向对象版本

都是七步,不变

面向对象,先分析有哪些对象,创建类,属性和方法


# 第一步:创建类
class WebServer:
	# 第四步:创建初始化方法,初始化套接字对象
	def __init__(self):
		# 1.创建套接字对象
		self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # AF_INET表示IPV4,SOCK_STREAM表示TCP协议

		# 2.绑定ip和端口号
		self.tcp_server_socket.bind(("127.0.0.1", 8000))  # 如果是本机,可以不写ip地址
		# 这里的8000端口不会随着服务器关闭而释放,需要设置端口复用,端口复用在下一篇笔记

		# 3.设置监听
		self.tcp_server_socket.listen(128)  # 128表示最大连接数

	# 第五步:定义一个start方法,启动服务器,接收客户端连接
	def start(self):
		while True:
			# 4.等待接受客户端的连接请求
			new_socket, ip_port = self.tcp_server_socket.accept()

			# 5.接收数据
			recv_data = new_socket.recv(1024).decode("utf-8")
			print(f"接收到的数据为:{recv_data}")

			# 6.发送数据
			new_socket.send("信息已收到".encode("utf-8"))

			# 7.关闭套接字(只能接收一次信息)
			# 不能关闭tcp_server_socket,否则无法继续接收新连接
			new_socket.close()

			# 目前一次只能接收一个客户端,因为是单进程
			# 如果希望服务器可以同时和多个客户端收发消息,需要多进程(多任务编程)

# 第二步:实例化对象
ws = WebServer()

# 第三步:调用start方法,启动服务器,接收客户端连接
ws.start()

端口复用

在上一次关闭服务器后,端口不会立即释放,需要设置端口复用,才能继续使用此端口

import socket

class WebServer:
    # 3、定义一个__init__方法,初始化套接字对象
    def __init__(self):
        self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 设置端口复用(在上一次关闭服务器后,端口不会立即释放,需要设置端口复用)
        self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)  # 参数2:SOL_SOCKET表示当前套接字对象,参数3:SO_REUSEADDR表示复用的地址,参数4:True表示开启端口复用(默认是false,要等待很长时间端口才会自动释放)
    
        self.tcp_server_socket.bind(("127.0.0.1", 8000))  # 如果是本机,可以不写ip地址
        self.tcp_server_socket.listen(128)  # 128表示最大连接数

    # 4、定义一个start方法,启动服务器,接收客户端连接
    def start(self):
        while True:
            # 等待接受客户端的连接请求
            new_socket, ip_port = self.tcp_server_socket.accept()

            # 调用自身的handle_request()方法,用于接收和发送消息(封装性)
            self.handle_request(new_socket, ip_port)

    # 5、定义一个handle_request方法,用于接收和发送消息
    def handle_request(self, new_socket, ip_port):
        # 接收某个客户端发送过来的消息
        recv_data = new_socket.recv(1024).decode("utf-8")  # 实际工作中一条数据大小在1~1.5k之间
        print(f"接收到的数据为:{recv_data}")

        # 发送消息给客户端
        new_socket.send("信息已收到".encode("utf-8"))

        # 关闭套接字
        new_socket.close()

# 定义一个程序的执行入口
if __name__ == "__main__":
    # 1、实例化服务器对象
    server = WebServer()

    # 2、启动服务器
    server.start()

开发注意事项

1.当TCP客户端程序想要和TCP服务端程序进行通信的时候必须要先建立连接
2.TCP客户端程序一般不需要绑定端口号,因为客户端是主动发起建立连接的。
3.TCP服务端程序必须绑定端口号,否则客户端找不到这个TCP服务端程序。
4.listen后的套接字是被动套接字,只负责接收新的客户端的连接请求,不能收发消息。
5.当TCP客户端程序和TCP服务端程序连接成功后,TCP服务器端程序会产生一个新的套接字,收发客户端消息使用该套接字。
6.关闭accept返回的套接字意味着和这个客户端已经通信完毕。
7.当客户端的套接字调用close后,服务器端的recv会解阻塞,返回的数据长度为O,服务端可以通过返回数据的长度来判断客户端是否
已经下线,反之服务端关闭套接字,客户端的recv也会解阻塞,返回的数据长度也为0。

UDP客户端

# 导入socket模块
import socket

# 创建UDP套接字对象
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 连接服务器,发送数据
udp_socket.sendto("消息".encode("utf-8"), ("127.0.0.1", 8000))

# 关闭套接字
udp_socket.close()

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

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

相关文章

我的JAVA-Web基础(2)

1.JDBC 防止sql注入 2.JSP JSP的基本语法 基本语法是 <% %> Java代码 <% %> 输出变量 可以转换成${变量}的EL表达式 <%! %>定义变量 JSP的基本语法包括以下几个主要部分&#xff1a; 1. 表达式&#xff08;Expression&#xff09; 表达式用于将…

新闻网站的个性化推荐:机器学习的应用

3.1可行性分析 开发者在进行开发系统之前&#xff0c;都需要进行可行性分析&#xff0c;保证该系统能够被成功开发出来。 3.1.1技术可行性 开发该新闻网站所采用的技术是vue和MYSQL数据库。计算机专业的学生在学校期间已经比较系统的学习了很多编程方面的知识&#xff0c;同时也…

IIC驱动EEPROM

代码参考正点原子 i2c_dri:主要是三段式状态机的编写 module iic_dri#(parameter SLAVE_ADDR 7b1010000 , //EEPROM从机地址parameter CLK_FREQ 26d50_000_000, //模块输入的时钟频率parameter I2C_FREQ 18d250_000 //IIC_SCL的时钟频率)( …

【动手学轨迹预测】2.3 场景表征方法

场景表征是指在所有可用的场景信息数据中, 提取出对于预测网络有用的数据, 并将其转换为易于模型学习的数据格式. 对于预测网络来说, 最重要的数据是交通参与者的历史轨迹和地图信息, 表达它们的常见方法有:栅格化和稀疏化 2.1.1 栅格化 多通道表达 如上图所示, 将历史轨迹和…

亚信安全举办“判大势 悟思想 强实践”主题党日活动

为深入学习和贯彻党的二十届三中全会精神&#xff0c;近日&#xff0c;亚信安全举办了 “学习贯彻党的二十届三中全会精神——‘判大势 悟思想 强实践’党日活动”&#xff0c;并取得圆满成功。 本次活动特邀南京市委宣讲团成员、南京市委党校市情研究中心主任王辉龙教授出席。…

医疗大模型威胁攻击下的医院AI安全:挑战与应对策略

一、引言 1.1 研究背景与意义 随着人工智能技术的迅猛发展,医疗大模型作为一种新兴的技术手段,正逐渐渗透到医疗领域的各个环节,为医疗服务的数字化转型带来了前所未有的机遇。从辅助诊断到疾病预测,从个性化治疗方案的制定到医疗资源的优化配置,医疗大模型展现出了巨大…

如何在谷歌浏览器中使用内置翻译功能

谷歌浏览器作为全球最受欢迎的网络浏览器之一&#xff0c;提供了强大且便捷的内置翻译功能。这一功能帮助用户轻松跨越语言障碍&#xff0c;浏览不同语言的网页内容。本文将详细介绍如何在谷歌浏览器中使用其内置翻译功能。 一、启用谷歌浏览器内置翻译功能 1、打开谷歌浏览器…

【MySQL】7.0 入门学习(七)——MySQL基本指令:帮助、清除输入、查询等

1.0 help &#xff1f; 帮助指令&#xff0c;查询某个指令的解释、用法、说明等。详情参考博文&#xff1a; 【数据库】6.0 MySQL入门学习&#xff08;六&#xff09;——MySQL启动与停止、官方手册、文档查询 https://www.cnblogs.com/xiaofu007/p/10301005.html 2.0 在cmd命…

基于推理的目标检测 DetGPT

基于推理的目标检测 DetGPT flyfish detgpt.github.io 近年来&#xff0c;由于大型语言模型&#xff08;LLMs&#xff09;的发展&#xff0c;计算机视觉领域取得了重大进展。这些模型使人类与机器之间能够进行更有效、更复杂的交互&#xff0c;为模糊人类与机器智能界限的新技…

概率论 期末 笔记

第一章 随机事件及其概率 利用“四大公式”求事件概率 全概率公式与贝叶斯公式 伯努利概型求概率 习题 推导 一维随机变量及其分布 离散型随机变量&#xff08;R.V&#xff09;求分布律 利用常见离散型分布求概率 连续型R.V相关计算 利用常见连续型分布的计算 均匀分布 正态…

探索 Python编程 调试案例:计算小程序中修复偶数的bug

在 学习Python 编程的过程里&#xff0c;会遇到各种各样的bug。而修复bug调试代码就像是一场充满挑战的侦探游戏。每一个隐藏的 bug 都是谜题&#xff0c;等待开发者去揭开真相&#xff0c;让程序可以顺利运行。今天&#xff0c;让我们通过一个实际案例&#xff0c;深入探索 Py…

Redis 介绍和安装

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 Redis 入门介绍 收录于专栏[redis] 本专栏旨在分享学习Linux的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 本章将带领读者进入 Redis 的世…

springboot480基于springboot高校就业招聘系统设计和实现(论文+源码)_kaic

摘 要 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&#xff0c;遇到了互联网时代才发现能补上自古…

【基础篇】1. JasperSoft Studio编辑器与报表属性介绍

编辑器介绍 Jaspersoft Studio有一个多选项卡编辑器&#xff0c;其中包括三个标签&#xff1a;设计&#xff0c;源代码和预览。 Design&#xff1a;报表设计页面&#xff0c;可以图形化拖拉组件设计报表&#xff0c;打开报表文件的主页面Source&#xff1a;源代码页码&#xff…

【河南新标】豫财预〔2024〕105号-《关于省级政务信息化建设项目支出预算标准的规定》-费用标准解读系列29

2024年12月3日&#xff0c;河南省财政厅发布了《关于省级政务信息化建设项目支出预算标准的规定》豫财预〔2024〕105号。《关于省级政务信息化建设项目支出预算标准的规定 &#xff08;试行&#xff09;》&#xff08;豫财预 〔2020〕81号&#xff09;同时废止。新的豫财预〔20…

导入numpy报错:PyCapsule_Import could not import module “datetime“

背景 docker部署深度学习算法时&#xff0c;安装miniconda报错&#xff0c;报线程错误。 然后在构建镜像时把miniconda装进去没有问题。 然后把环境移进去发现报numpy导入错误 在python解释器尝试导入numpy发现还是报错 尝试重新装numpy&#xff0c;发现没有解决。 网上找解决方…

TANGO与LabVIEW控制系统集成

TANGO 是一个开源的设备控制和数据采集框架&#xff0c;主要用于管理实验室设备、自动化系统和工业设备。它为不同类型的硬件提供统一的控制接口&#xff0c;并支持设备之间的通信&#xff0c;广泛应用于粒子加速器、同步辐射光源、实验室自动化和工业控制等领域。 1. TANGO的核…

利用Circuit JS1再学学电子方面的知识(硬件)

1 电阻器 1.1 电阻并联 每个电阻电压相同&#xff0c;总电流等于各支路电流之和。 并联电阻值 R 1/(1/R11/R2);R约等于90.9 电阻并联后的阻值比最小的一个电阻值都小。 1.2 电阻串联 电阻串联的阻值为各电阻阻值相加。 RR1R2&#xff0c;串联涉及电阻分压。 一般在开关处…

使用Amazon Bedrock的无服务器的智能工作流

使用Amazon Bedrock的无服务器的智能工作流 智能工作流基于用户输入处理不可预见的任务&#xff0c;比如发起API调用。无服务器架构可以高效地管理这些任务和不同的工作负载&#xff0c;而无需维护服务器&#xff0c;从而加快部署速度。 你将学习如何通过使用带有保护措施的智能…

国高材服务 | 高分子结晶动力学表征——高低温热台偏光显微镜

众所周知&#xff0c;聚合物制品的实际使用性能&#xff08;如光学透明性、硬度、模量等&#xff09;与材料内部的结晶形态、晶粒大小及完善程度有着密切的联系&#xff0c;因此&#xff0c;对聚合物结晶形态等的研究具有重要的理论和实际意义。 随着结晶条件的不用&#xff0c…