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

server/2024/12/28 18:54:59/

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 socketclass 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.ppmy.cn/server/152810.html

相关文章

Tomcat负载均衡全解析

一、Java项目概述 (一)Java语言特点 Java是一种计算机应用语言,在开发王者和管理系统等方面有着广泛的应用。它具有开源免费的特性,不过需要注意的是,虽然语言本身开源,但是后期开发工具可能会收取费用。 (二)、JDK和Tomcat 1,JDK:作为Java语言的开发工具,在Linu…

SpringBoot如何实现缓存预热?

缓存预热是指在 Spring Boot 项目启动时&#xff0c;预先将数据加载到缓存系统&#xff08;如 Redis&#xff09;中的一种机制。 那么问题来了&#xff0c;在 Spring Boot 项目启动之后&#xff0c;在什么时候&#xff1f;在哪里可以将数据加载到缓存系统呢&#xff1f; 实现…

深度学习在语音识别中的应用

引言 语音识别技术是人工智能领域中的一个重要分支&#xff0c;它使得机器能够理解和转换人类的语音为文本。深度学习的出现极大地推动了语音识别技术的发展。本文将介绍如何使用深度学习构建一个基本的语音识别系统&#xff0c;并提供一个实践案例。 环境准备 在开始之前&a…

SpringBoot——核心概念

文章目录 一.核心概念IoC/DI思想2.Ioc容器3.Bean 二.IoC入门案例三.DI入门案例分析四.bean基础配置五.bean的实例化&#xff08;创建&#xff09;六.bean实例化——静态工厂七.bean实例化——示例工程与FactoryBean八.bean的生命周期九.依赖注入的两种方式十.构造器注入十一.依…

使用echarts 绘制县级以下 乡镇地图并标注若干坐标点。获取县级以下乡镇的边界坐标

最终效果&#xff1a; 要做一个乡镇级的地图&#xff0c;并标出某些企业的坐标点。 1、使用高德&#xff0c;但高德不支持县级以下。放弃 2、使用echarts 图表 但是使用地理坐标系时&#xff0c;我还是没有乡镇的边界线经纬度。首先要获取边界线啊&#xff0c;方法如下&#…

云手机方案全解析

助力账号注册登录 在 TikTok 账号注册及登录方面&#xff0c;云手机发挥着至关重要的作用。由于 TikTok 平台对网络环境要求严格&#xff0c;只有国外环境才能使用&#xff0c;云手机则能够通过模拟海外环境来解决这一难题&#xff0c;它可以依据代理设置直接生成相应的语言、定…

Linux之压缩解压相关命令

1、gzip/gunzip 作用&#xff1a;压缩和解压文件 语法&#xff1a; #压缩 压缩后缀是.gz gzip 文件 # 解压 gunzip 文件.gz 注意&#xff1a; (1)只能压缩文件不能压缩目录 (2)不保留原来的文件 (3)同时多个文件会产生多个压缩包 2、zip/unzip 作用&#xff1a;压缩和解压…

WebSocket了解

WebSocket 定义与概述 定义&#xff1a;WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。它使得客户端和服务器之间的数据交互更加实时、高效&#xff0c;能够在浏览器和服务器之间建立持久的连接&#xff0c;允许双向数据传输。背景与目的&#xff1a;传统的 HTTP 协…