Python学习之网络编程
一,网络编程基本概念
网络编程是通过编写代码实现计算机之间的通信,它涵盖了许多重要的概念和技术,以下是一些关键概念的介绍:
1. Socket(套接字)
-
定义:Socket是计算机网络中用于进行通信的端点,它提供了一个应用层与传输层之间的接口。通过Socket,程序可以与其他计算机进行数据交换。
-
作用:通过Socket,程序能够进行以下操作:创建连接、发送和接收数据、关闭连接等。最常见的Socket编程模型是基于TCP/IP协议的。
-
类型:
- TCP Socket:面向连接的,使用TCP协议进行通信,确保数据的可靠性。
-
UDP Socket:无连接的,使用UDP协议进行通信,适用于实时性要求较高的应用,但不能保证数据的可靠性。
2. IP地址与端口
- IP地址:每台连接到网络的设备都会分配一个唯一的IP地址(互联网协议地址),用于标识设备的网络位置。IP地址可以是IPv4(32位)或IPv6(128位)。
- 端口号:端口号是区分同一台设备上不同服务的标识符。在一个IP地址下,可以有多个端口,通常端口号范围是0到65535,其中0到1023是“知名端口”,如HTTP(80)、HTTPS(443)、FTP(21)等。
3. TCP/IP协议栈
TCP/IP协议栈是现代计算机网络的基础。它分为多个层级,常见的有四层:
- 应用层:处理具体的应用协议,如HTTP、FTP、SMTP等。
- 传输层:提供端到端的通信功能,主要协议为TCP(传输控制协议)和UDP(用户数据报协议)。
- 网络层:负责数据包的路由和传输,核心协议为IP(互联网协议)。
- 数据链路层:在物理介质上传输数据包,确保数据的可靠传输。
4. TCP与UDP
-
TCP(传输控制协议):
- 面向连接:在发送数据前,必须建立连接(如通过三次握手过程)。
- 可靠性:TCP保证数据的可靠性,通过确认(ACK)、重传机制、顺序控制等手段来确保数据按顺序且无误到达。
- 应用:适用于需要高可靠性的应用,如网页浏览(HTTP)、文件传输(FTP)等。
-
UDP(用户数据报协议):
- 无连接:无需建立连接,直接发送数据。
- 不保证可靠性:UDP不保证数据的可靠到达,也不保证数据的顺序,适用于对实时性要求高的应用(如视频会议、实时游戏等)。
- 应用:常用于实时通信、流媒体传输等场景。
5. 三次握手与四次挥手
-
三次握手(TCP连接建立过程):
- SYN:客户端向服务器发送连接请求(SYN标志位)。
- SYN-ACK:服务器响应客户端的请求,并确认收到连接请求。
- ACK:客户端向服务器确认连接建立完毕,连接正式建立。
-
四次挥手(TCP连接关闭过程):
- 客户端发起连接关闭请求(FIN标志位)。
- 服务器响应并确认(ACK)。
- 服务器关闭连接并发送FIN请求。
- 客户端确认关闭连接。
6. DNS(域名系统)
- 定义:DNS是一种将域名(如www.example.com)转换为IP地址(如192.168.1.1)的系统。因为人类更容易记住域名而不是数字形式的IP地址,所以DNS提供了一个可读性更强的映射。
- 工作原理:当用户访问一个网站时,计算机会查询DNS服务器,获取域名对应的IP地址,之后通过这个IP地址与服务器建立连接。
7. HTTP与HTTPS
- HTTP(超文本传输协议):HTTP是Web的基础协议,用于客户端与服务器之间的请求和响应。它是无状态的,每次请求都是独立的。
- HTTPS(安全超文本传输协议):HTTPS是在HTTP上加入了SSL/TLS协议,提供了加密和身份验证功能,确保数据传输的安全性,防止中间人攻击。
8. WebSocket
- 定义:WebSocket是一种基于TCP的协议,允许在客户端和服务器之间建立持久的双向通信。与传统的HTTP不同,WebSocket支持实时数据交换,适用于需要实时更新的应用场景,如在线聊天、实时股票交易等。
9. 代理服务器与负载均衡
- 代理服务器:代理服务器位于客户端和目标服务器之间,转发客户端的请求到目标服务器。它可以隐藏客户端的真实IP地址,增强安全性,或者缓存数据以提高访问速度。
- 负载均衡:负载均衡是一种技术,通过将请求分配到多个服务器来分散负载,保证应用的高可用性和高性能。
10. 网络安全
- 加密与解密:在传输过程中,数据可能会被窃取。加密可以保证数据的保密性,常用的加密算法有对称加密(如AES)和非对称加密(如RSA)。
- 身份验证与授权:确保通信双方身份的合法性,并根据授权控制对资源的访问,常见方法有使用证书、OAuth等。
- 防火墙:防火墙可以监控和过滤网络流量,防止恶意访问或攻击。
二,网络协议概述
1. OSI模型与TCP/IP模型
网络协议通常是按照网络协议模型来设计的,最经典的模型是OSI七层模型和TCP/IP协议栈。两者在结构上有所不同,但目的都是为了标准化网络通信。
- OSI七层模型:
- 物理层(Physical Layer):定义物理设备的传输媒介,如电缆、光纤等。
- 数据链路层(Data Link Layer):提供节点到节点的通信,常用协议如Ethernet、PPP。
- 网络层(Network Layer):负责数据包的路由与转发,核心协议是IP协议(Internet Protocol)。
- 传输层(Transport Layer):提供端到端的数据传输,常见协议有TCP、UDP。
- 会话层(Session Layer):管理应用间的会话和数据交换,典型协议有NetBIOS。
- 表示层(Presentation Layer):数据格式的转换,如加密、解密等。
- 应用层(Application Layer):实现具体的应用协议,如HTTP、FTP、SMTP等。
- TCP/IP协议栈:
- 包括应用层、传输层、网络层和数据链路层,实际网络协议栈中的层次较为简化。
2. 常见的网络协议
1. IP协议(Internet Protocol)
- IP协议是网络层协议,负责在网络中传输数据包。它的主要作用是路由:根据目标IP地址,将数据从源计算机发送到目的计算机。IP协议有两个版本:
- IPv4(32位地址,表示范围为0.0.0.0到255.255.255.255);
- IPv6(128位地址,表示范围非常大,解决了IPv4地址耗尽的问题)。
2. TCP协议(Transmission Control Protocol)
- TCP协议是传输层的面向连接的协议。它提供可靠的、无差错的数据传输。TCP保证数据包按顺序到达,并支持错误检测、重传和流量控制。TCP广泛用于需要高可靠性的应用,如网页浏览(HTTP)、电子邮件(SMTP)等。
- 三次握手:建立连接时,客户端和服务器通过三次握手过程确认通信准备就绪。
- 四次挥手:断开连接时,客户端和服务器通过四次挥手关闭连接。
3. UDP协议(User Datagram Protocol)
- UDP协议是传输层的无连接协议。与TCP不同,UDP不保证数据的可靠到达和顺序,适用于实时应用,如视频流、语音通信等。UDP传输效率较高,但可能出现数据丢失和乱序的情况。
- TCP与UDP的对比
特性 | TCP | UDP |
---|---|---|
连接方式 | 面向连接,需建立连接 | 无连接,直接发送数据 |
可靠性 | 保证数据可靠传输 | 不保证数据可靠性 |
数据顺序 | 保证数据顺序到达 | 不保证数据顺序 |
流量控制 | 支持流量控制 | 不支持流量控制 |
拥塞控制 | 支持拥塞控制 | 不支持拥塞控制 |
传输效率 | 较低,因需要建立连接和进行错误处理 | 较高,适合低延迟要求的应用 |
数据重传 | 自动重传丢失的数据包 | 不进行重传 |
头部大小 | 20字节(不含数据) | 8字节 |
适用场景 | 文件传输、网页浏览、电子邮件等 | 实时通信、视频会议、在线游戏等 |
4. HTTP协议(HyperText Transfer Protocol)
- HTTP协议是应用层的协议,用于客户端与Web服务器之间的请求和响应。它基于请求/响应模型,不保证数据传输的可靠性,因此常与TCP/IP一起使用。HTTPS是其安全版本,使用TLS/SSL协议加密传输数据,确保通信的安全。
5. DNS协议(Domain Name System)
- DNS协议是用于将域名(如www.example.com)解析为IP地址的协议。用户通过域名访问网站时,DNS会将域名转换为相应的IP地址,从而完成路由。
6. FTP协议(File Transfer Protocol)
- FTP协议是用于在计算机之间传输文件的协议。它工作在客户端和服务器之间,支持上传、下载文件。FTP支持两种模式:主动模式和被动模式。
7. SMTP协议(Simple Mail Transfer Protocol)
- SMTP协议是用于电子邮件传输的协议。它负责在邮件服务器之间传送邮件,通常与POP3或IMAP协议配合使用,POP3/IMAP用于邮件的接收和存储。
8. POP3/IMAP协议
- POP3和IMAP都是用于电子邮件接收的协议:
- POP3:将邮件从邮件服务器下载到本地设备,下载后邮件通常从服务器删除。
- IMAP:将邮件存储在邮件服务器上,用户可以在不同设备上查看邮件,邮件在服务器上保持不变。
9. ARP协议(Address Resolution Protocol)
- ARP协议用于在局域网内解析IP地址与MAC地址的映射关系。当一个设备知道目标IP地址时,ARP协议帮助它找到目标设备的MAC地址,从而完成数据链路层的通信。
10. DHCP协议(Dynamic Host Configuration Protocol)
- DHCP协议用于动态分配IP地址给网络中的设备。设备在连接到网络时,DHCP服务器为其分配一个IP地址、子网掩码、网关等网络配置。
3. 网络协议的作用和特性
- 数据格式化:协议规定了数据的格式、结构以及传输顺序。
- 错误检测和修正:大多数协议会包含机制来检测和修复传输中的错误,特别是像TCP这样的可靠协议。
- 数据加密与安全性:协议可以通过加密机制来保证数据在传输过程中的安全性,如HTTPS协议。
- 路由和流量控制:某些协议,如IP协议,负责在网络中转发数据包,确保数据包能够到达目的地。传输层协议如TCP还会进行流量控制和拥塞管理。
4. 协议的分类
根据协议的作用和层级,网络协议大致可以分为:
- 应用层协议:直接为应用程序提供服务,如HTTP、FTP、DNS、SMTP等。
- 传输层协议:处理端到端的通信,确保数据的可靠传输,如TCP和UDP。
- 网络层协议:负责数据包的路由和传输,如IP协议。
- 数据链路层协议:确保在物理链路上正确传输数据,如Ethernet、PPP等。
三,Socket详解
Socket(套接字)是计算机网络中用于实现数据通信的基本组件,它为程序提供了一个接口,通过这个接口,应用程序可以向网络上的其他设备发送和接收数据。简而言之,Socket是通信的“端点”,它通过网络协议(如TCP或UDP)与其他计算机进行通信。
Socket编程通常是实现客户端与服务器之间通信的关键技术之一。以下是Socket的详细介绍,包括其基本概念、类型、工作原理以及如何在实际应用中使用。
1. Socket的基本概念
什么是Socket?
Socket是一个抽象的网络通信接口,通过它,应用程序可以通过操作系统提供的网络协议与其他主机进行通信。它是程序和协议之间的一个抽象层,提供了对网络通信的简单操作接口。通过Socket,程序可以完成:
- 打开网络连接
- 向网络发送和接收数据
- 关闭连接
每个Socket都需要指定通信的协议(如TCP或UDP)和相应的端口号,系统将根据这些信息来正确地路由数据。
Socket的组成
Socket通常由以下几部分组成:
- IP地址:标识计算机在网络中的位置,通常是一个IPv4或IPv6地址。
- 端口号:用于区分同一台机器上不同的服务或应用程序,端口号通常在0到65535之间,0到1023是“知名端口”。
- 协议类型:TCP(面向连接,可靠)或UDP(无连接,不可靠)。
2. Socket的类型
根据协议的不同,Socket可以分为以下几种类型:
1. 流式Socket(Stream Socket)
- 协议:TCP
- 特点:流式Socket是面向连接的,数据传输保证顺序、可靠性和完整性。通信前必须先建立连接,通信过程中保证数据无误。
- 应用场景:适用于需要高可靠性、顺序保证的应用,如HTTP、FTP、SMTP等。
2. 数据报Socket(Datagram Socket)
- 协议:UDP
- 特点:数据报Socket是无连接的,数据包可能丢失、乱序、重复,发送方不会等待接收方确认。其优势是传输速度快,但不可靠。
- 应用场景:适用于实时性要求较高、容忍丢包的应用,如视频会议、在线游戏、DNS查询等。
3. 原始Socket(Raw Socket)
- 协议:ICMP、IP等
- 特点:原始Socket允许应用程序直接访问底层网络协议,如IP协议。它通常用于需要构造和发送自定义网络数据包的应用。
- 应用场景:网络安全(如防火墙、嗅探器)、网络测试工具等。
3. Socket的工作原理
Socket的工作过程通常分为两个部分:客户端和服务器。下面是Socket在客户端和服务器端的基本工作流程。
1. 服务器端Socket流程
- 创建Socket:服务器端创建一个Socket对象,指定协议(通常是TCP)。
- 绑定端口:服务器通过
bind()
方法将Socket与指定的IP地址和端口号绑定。 - 监听连接:服务器调用
listen()
方法,进入监听状态,等待客户端的连接请求。 - 接受连接:当客户端请求连接时,服务器通过
accept()
方法接受连接,并创建一个新的Socket对象与客户端进行通信。 - 接收和发送数据:服务器和客户端之间通过
recv()
和send()
方法交换数据。 - 关闭连接:通信结束后,服务器调用
close()
方法关闭Socket连接。
2. 客户端Socket流程
- 创建Socket:客户端首先创建一个Socket对象,指定协议(通常是TCP)。
- 连接服务器:客户端通过
connect()
方法与服务器建立连接,指定目标IP地址和端口号。 - 发送请求:客户端通过
send()
方法发送请求数据到服务器。 - 接收响应:客户端通过
recv()
方法接收服务器的响应数据。 - 关闭连接:通信完成后,客户端通过
close()
方法关闭Socket连接。
4. 常用Socket API
以下是常见的Socket操作及其使用方式。以Python为例,Java、C等语言也有类似的API:
1. Python中的Socket API
-
创建Socket:
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # AF_INET表示IPv4,SOCK_STREAM表示TCP
-
绑定IP和端口:
s.bind(('localhost', 12345)) # 绑定到本地IP和端口
-
监听连接:
s.listen(5) # 最多允许5个连接排队
-
接受连接:
client_socket, client_address = s.accept() # 等待客户端连接
-
连接到服务器(客户端):
s.connect(('localhost', 12345)) # 连接到指定的服务器和端口
-
发送数据:
s.send(b'Hello, World!') # 发送数据,数据必须是字节串
-
接收数据:
data = s.recv(1024) # 接收最多1024字节的数据
-
关闭连接:
s.close() # 关闭Socket连接
2. 主要的Socket方法
socket()
:创建一个新的Socket对象。bind(address)
:将Socket与指定的地址(IP地址和端口号)绑定。listen(backlog)
:开始监听连接。backlog
指定最大排队连接数。accept()
:接受一个新的连接请求,返回一个新的Socket对象和客户端的地址。connect(address)
:客户端连接到指定的服务器地址。send(data)
:发送数据到远程计算机。recv(buffer_size)
:接收从远程计算机发送的数据。close()
:关闭Socket连接。
5. Socket的应用示例
1. 简单的TCP客户端和服务器
TCP服务器(Python示例)
import socket
# 创建Socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定地址和端口
server_socket.bind(('localhost', 12345))
# 开始监听连接
server_socket.listen(5)
print('Server is listening...')
while True:
# 接受连接
client_socket, client_address = server_socket.accept()
print(f'Connection from {client_address} has been established.')
# 接收客户端数据
data = client_socket.recv(1024)
print(f'Received from client: {data.decode()}')
# 发送响应
client_socket.send(b'Hello, Client!')
# 关闭连接
client_socket.close()
TCP客户端(Python示例)
import socket
# 创建Socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接到服务器
client_socket.connect(('localhost', 12345))
# 发送数据
client_socket.send(b'Hello, Server!')
# 接收响应
response = client_socket.recv(1024)
print(f'Received from server: {response.decode()}')
# 关闭连接
client_socket.close()
四,Socket模块
1. 基本概念
在socket
模块中,最重要的概念是Socket对象。它代表了一个网络通信的端点,通过该对象可以与其他计算机上的应用程序进行通信。Socket对象通常由以下参数组成:
- 地址族(Address Family):表示Socket使用的地址类型。
socket.AF_INET
:IPv4地址族。socket.AF_INET6
:IPv6地址族。socket.AF_UNIX
:Unix域套接字。
- 套接字类型(Socket Type):定义Socket使用的通信协议。
socket.SOCK_STREAM
:TCP协议,面向连接的流式通信。socket.SOCK_DGRAM
:UDP协议,无连接的报文传输。
- 协议:一般情况下由操作系统根据地址族和套接字类型自动选择协议。
2. 常用的socket方法
2.1 创建Socket
import socket
# 创建一个IPv4、TCP的Socket对象
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.AF_INET
:表示使用IPv4地址。socket.SOCK_STREAM
:表示使用TCP协议。
2.2 绑定地址和端口 (bind
)
服务器需要通过bind()
方法将Socket绑定到指定的IP地址和端口号上。
s.bind(('localhost', 12345)) # 绑定IP和端口
- 第一个参数是一个元组,包含了服务器的IP地址和端口号。
localhost
表示本地计算机,12345
是监听的端口。
2.3 开始监听连接 (listen
)
服务器端调用listen()
方法来开启监听状态,等待客户端连接。
s.listen(5) # 允许最多5个客户端连接
5
表示服务器可以同时处理的最大排队连接数。
2.4 接受客户端连接 (accept
)
服务器端通过accept()
方法接受客户端的连接请求。
client_socket, client_address = s.accept() # 接受连接
print(f"Connection from {client_address}")
accept()
方法会阻塞,直到客户端发起连接。它返回一个新的Socket对象和客户端的地址。
2.5 客户端连接 (connect
)
客户端通过connect()
方法与服务器建立连接,指定服务器的IP和端口。
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('localhost', 12345)) # 连接服务器
2.6 发送数据 (send
和 sendall
)
通过send()
方法发送数据。数据必须是字节(bytes
)格式。
client_socket.send(b'Hello, Server!') # 发送字节数据
send()
发送的数据可能没有完全发送完,如果需要确保数据完整发送,建议使用sendall()
。
client_socket.sendall(b'Hello, Server!') # 确保发送完数据
2.7 接收数据 (recv
)
recv()
方法用于接收数据。它返回的是字节数据。
data = client_socket.recv(1024) # 接收最多1024字节的数据
print(f"Received: {data.decode()}") # 解码为字符串并打印
recv()
方法的参数是缓冲区的大小,表示每次最多接收多少字节的数据。
2.8 关闭Socket连接 (close
)
通信完成后,调用close()
方法关闭Socket连接。
client_socket.close()
3. 示例:TCP服务器与客户端
3.1 TCP服务器端(Python示例)
import socket
def start_server():
# 创建一个TCP Socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定IP和端口
server_socket.bind(('localhost', 12345))
# 开始监听客户端连接
server_socket.listen(5)
print('Server is listening...')
while True:
# 接受客户端连接
client_socket, client_address = server_socket.accept()
print(f'Connection from {client_address}')
# 接收数据
data = client_socket.recv(1024)
if data:
print(f'Received: {data.decode()}')
# 发送响应数据
client_socket.sendall(b'Hello, Client!')
# 关闭客户端连接
client_socket.close()
if __name__ == '__main__':
start_server()
3.2 TCP客户端(Python示例)
import socket
def start_client():
# 创建一个TCP Socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接到服务器
client_socket.connect(('localhost', 12345))
# 发送数据
client_socket.sendall(b'Hello, Server!')
# 接收服务器响应
response = client_socket.recv(1024)
print(f'Received from server: {response.decode()}')
# 关闭连接
client_socket.close()
if __name__ == '__main__':
start_client()
4. UDP通信
UDP通信不需要建立连接,发送数据和接收数据非常简单。下面是一个简单的UDP服务器和客户端示例。
4.1 UDP服务器端(Python示例)
import socket
def start_udp_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 创建UDP Socket
# 绑定IP和端口
server_socket.bind(('localhost', 12345))
print('Server is waiting for messages...')
while True:
# 接收数据
data, client_address = server_socket.recvfrom(1024)
print(f'Received message: {data.decode()} from {client_address}')
# 发送响应数据
server_socket.sendto(b'Hello, Client!', client_address)
if __name__ == '__main__':
start_udp_server()
4.2 UDP客户端(Python示例)
import socket
def start_udp_client():
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 创建UDP Socket
# 发送数据
client_socket.sendto(b'Hello, Server!', ('localhost', 12345))
# 接收响应
data, server_address = client_socket.recvfrom(1024)
print(f'Received from server: {data.decode()}')
# 关闭连接
client_socket.close()
if __name__ == '__main__':
start_udp_client()
5. 其他常用功能
5.1 设置Socket超时 (settimeout
)
settimeout()
方法可以设置Socket的超时时间,单位为秒。超时后,recv()
或accept()
等方法将抛出socket.timeout
异常。
s.settimeout(5) # 设置超时时间为5秒
5.2 获取本地地址 (getsockname
)
getsockname()
方法可以获取当前Socket的本地地址。
address = s.getsockname()
print(f'Local address: {address}')
5.3 获取远程地址 (getpeername
)
getpeername()
方法可以获取当前Socket连接的远程地址。
address = s.getpeername()
print(f'Remote address: {address}')
6. 总结
- Python的
socket
模块提供了丰富的功能,能够实现基于TCP和UDP协议的网络通信。 - 使用
socket
模块,你可以轻松创建客户端和服务器应用程序,进行数据发送和接收。 - 常见的Socket方法包括
bind()
、listen()
、accept()
、connect()
、send()
、recv()
等。 - 对于UDP通信,
sendto()
和recvfrom()
代替了send()
和recv()
,且不需要建立连接。
五,TCP编程
1. TCP服务器编程步骤
- 创建Socket对象:使用
socket.socket()
创建一个Socket对象,指定地址族为IPv4(AF_INET
)和协议为TCP(SOCK_STREAM
)。 - 绑定端口:使用
bind()
方法将Socket绑定到一个IP地址和端口上。 - 监听连接:使用
listen()
方法让服务器开始监听客户端的连接请求。 - 接受连接:通过
accept()
方法接受客户端的连接请求。 - 数据传输:通过
recv()
接收客户端数据,使用send()
或sendall()
发送数据到客户端。 - 关闭连接:通信完成后,调用
close()
方法关闭Socket连接。
实例一,TCP服务端编程编写
from socket import socket,AF_INET,SOCK_STREAM
#AF_INET 用于Internet之间的进程通信
#SOCK_STREAM 表示为TCP协议编程
#1,创建socket对象
server_socket=socket(AF_INET,SOCK_STREAM)
#2,绑定IPA地址和端口
ip='127.0.0.1'
port=8888
server_socket.bind((ip,port))
#3,使用listen()开始监听
server_socket.listen(5)
print('服务器已经启动')
#4,等待客户端的连接
client_socket,client_addr=server_socket.accept() #系列解包赋值
#5,接受来自客户端的数据
date=client_socket.recv(1024)
print('客户端发送过来的数据为date',date.decode('utf-8')) #要求客户端发送过来的数据使用utf-8编码
#6,关闭socket
server_socket.close()
2.TCP客户端编程基本流程
- 创建Socket对象:客户端通过
socket.socket()
创建一个Socket对象,并指定使用的地址族(通常是IPv4)和协议(通常是TCP)。 - 连接服务器:客户端通过
connect()
方法与服务器建立连接,指定服务器的IP地址和端口号。 - 发送数据:客户端使用
send()
或sendall()
方法将数据发送到服务器。 - 接收数据:客户端通过
recv()
方法接收服务器返回的响应数据。 - 关闭连接:通信结束后,客户端使用
close()
方法关闭Socket连接。
实例二,TCP客户端编程编写
要求新创建一个项目编写python代码,以便作为区分。并且新开启一个窗口以打开这个新python文件
import socket
#1,创建socket对象
client_socket=socket.socket()
#2,写入服务端IP地址与主机端口
ip='127.0.0.1'
port=8888
client_socket.connect((ip,port))
print('与服务器连接建立成功')
#3,发送数据
client_socket.send('hello python'.encode('utf-8'))
#4,关闭
client_socket.close()
print('发送完毕')
TCP编程客户端启动运行有先后,先启动运行服务端再启动运行客户端,连接建立之后双方谁先发送数据均可
实例三,TCP多次通信服务器端代码编写
import socket
#1,创建socket对象
socket_obj=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#2,绑定主机IP端口
socket_obj.bind(('127.0.0.1',8888))
#3,设置最大的连接数量
socket_obj.listen(5)
#4,等待客户端的TCP连接
client_socket,client_addr=socket_obj.accept()
#5,接受数据
info=socket_obj.recv(1024).decode('utf-8')
while info != 'bye':
if info != '':
print('接受到的数据是:',info)
#准备发送数据
date=input('请输入要发送的数据:')
#服务器端回复客户端
socket_obj.send(date.encode('utf-8'))
if date == 'bye':
break
info=socket_obj.recv(1024).decode('utf-8')
#关闭socket对象
client_socket.close()
socket_obj.close()
实例四,TCP多次通信客户器端代码编写
import socket
#1,创建socket对象
client_socket=socket.socket()
#2,主机的IP与端口
client_socket.connect(('127.0.0.1',8888))
print('已经建立服务器连接')
#3,客户端先发送数据
info=''
while info !='bye':
#准备发送的数据
send_data=input('请输入要发送的数据:')
client_socket.send(send_data.encode('utf-8'))
#判断
if send_data=='bye':
break
#接收一条数据
info=client_socket.recv(1024).decode('utf-8')
print('接受到服务器的响应数据:',info)
#关闭socket对象
client_socket.close()
常见TCP客户端的改进和扩展
1. 设置Socket超时(settimeout
)
客户端可以通过settimeout()
方法设置Socket的超时时间。如果在指定时间内没有收到响应,recv()
方法会抛出socket.timeout
异常。
client_socket.settimeout(5) # 设置5秒超时
- 超过5秒没有数据接收,
recv()
方法会抛出timeout
异常。
2. 发送和接收更大的数据
如果需要发送或接收比1024字节更大的数据,可以调整缓冲区大小,或者分多次发送和接收。
client_socket.sendall(b"Large Data" * 1000) # 发送更大的数据
3. 异常处理
在实际应用中,TCP客户端应处理可能的异常,如连接失败、发送失败等。
try:
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('localhost', 12345))
except socket.error as e:
print(f"Error occurred: {e}")
finally:
client_socket.close()
- 通过
try-except-finally
语句捕获并处理Socket异常。
3 TCP服务端(线程池方式)
为了更有效地管理多个客户端连接,可以使用线程池来代替创建一个新的线程。
import socket
import threading
from concurrent.futures import ThreadPoolExecutor
# 处理客户端连接的函数
def handle_client(client_socket, client_address):
print(f"New connection from {client_address}")
# 接收客户端数据
data = client_socket.recv(1024) # 接收最多1024字节的数据
print(f"Received from {client_address}: {data.decode()}")
# 发送响应
client_socket.sendall(b"Hello, Client!")
# 关闭连接
client_socket.close()
print(f"Connection with {client_address} closed.")
def start_tcp_server():
# 1. 创建Socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 绑定IP和端口
server_socket.bind(('localhost', 12345))
# 3. 开始监听连接,最多允许5个客户端排队
server_socket.listen(5)
print("Server is listening on port 12345...")
# 4. 创建线程池来管理客户端连接
with ThreadPoolExecutor(max_workers=5) as executor:
# 5. 处理多个客户端连接
while True:
# 接受客户端连接
client_socket, client_address = server_socket.accept()
# 将每个连接任务提交给线程池
executor.submit(handle_client, client_socket, client_address)
if __name__ == "__main__":
start_tcp_server()
解释:
ThreadPoolExecutor
:通过线程池来管理线程,避免每次都创建新的线程。executor.submit()
:将处理客户端连接的任务提交给线程池中的空闲线程执行。
4. TCP服务端异常处理
在实际编程中,TCP服务端程序需要处理一些可能出现的异常,例如:
- 客户端断开连接
- 网络异常
- 连接超时
可以通过try
/except
语句来捕获异常并进行处理。例如:
try:
client_socket, client_address = server_socket.accept()
except socket.timeout:
print("Connection timeout!")
except Exception as e:
print(f"Error: {e}")
六,UDP编程
UDP(用户数据报协议)是一个无连接的协议,与TCP不同,UDP不需要建立连接和确认数据是否成功到达,因此它的传输效率更高,但也不保证数据的可靠性和顺序性。在UDP中,数据被以“数据报”的形式发送,每个数据报都包含了目的地址和端口信息。
UDP编程相较于TCP编程简单,因为它不需要进行连接的建立与关闭。下面我们将介绍如何使用Python的socket
模块进行UDP编程。
UDP客户端与服务器编程流程
- 创建UDP Socket对象:使用
socket.socket()
方法创建一个UDP的Socket对象。 - 绑定端口(仅服务器端需要):服务器端需要通过
bind()
方法将Socket与IP地址和端口绑定。 - 发送数据:客户端通过
sendto()
方法发送数据,数据将发送到目标IP地址和端口。 - 接收数据:使用
recvfrom()
方法接收来自远程主机的数据。 - 关闭连接:UDP没有连接的概念,但客户端和服务器使用
close()
来关闭Socket。
1. UDP服务器端编程
1.1 UDP服务器端代码
服务器端代码将创建一个UDP套接字,绑定本地IP和端口,接收客户端数据,并发送响应。
import socket
def start_udp_server():
# 1. 创建UDP套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2. 绑定IP和端口
server_socket.bind(('localhost', 12345))
print("UDP server is waiting for messages...")
while True:
# 3. 接收客户端数据
data, client_address = server_socket.recvfrom(1024) # 最大接收1024字节
print(f"Received message from {client_address}: {data.decode()}")
# 4. 发送响应数据
server_socket.sendto(b"Hello, Client!", client_address)
if __name__ == "__main__":
start_udp_server()
代码解析:
socket.AF_INET
:使用IPv4地址族。socket.SOCK_DGRAM
:使用UDP协议。bind(('localhost', 12345))
:将Socket绑定到localhost
的12345
端口。recvfrom(1024)
:接收客户端发送的数据,最多1024字节,返回的是数据和客户端的地址(client_address
)。sendto(b"Hello, Client!", client_address)
:向客户端发送数据,client_address
指定了客户端的地址和端口。
2. UDP客户端编程
2.1 UDP客户端代码
客户端创建一个UDP套接字,发送数据到服务器,并接收来自服务器的响应。
import socket
def start_udp_client():
# 1. 创建UDP套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2. 发送数据到服务器
message = "Hello, Server!"
client_socket.sendto(message.encode(), ('localhost', 12345)) # 发送数据到服务器
# 3. 接收服务器的响应
response, server_address = client_socket.recvfrom(1024) # 接收来自服务器的响应
print(f"Received from server: {response.decode()}")
# 4. 关闭连接
client_socket.close()
if __name__ == "__main__":
start_udp_client()
代码解析:
socket.AF_INET
:使用IPv4地址族。socket.SOCK_DGRAM
:使用UDP协议。sendto(message.encode(), ('localhost', 12345))
:通过sendto()
方法将数据发送到指定的服务器IP和端口。发送的数据必须是字节类型,因此需要调用encode()
。recvfrom(1024)
:接收来自服务器的数据,最多接收1024字节,并返回数据和服务器的地址。close()
:关闭Socket连接。
3. UDP编程的特点与优势
- 无连接性:UDP是无连接的协议,客户端和服务器不需要进行连接的建立和拆除。发送数据时无需确认接收方是否准备好接收。
- 简单快速:由于没有连接的开销,UDP适合实时性要求高、数据量较小、丢包可以容忍的场景,例如视频流、语音通信、在线游戏等。
- 不保证可靠性:UDP不会确保数据包的到达、顺序或完整性,数据包可能会丢失、重复或者顺序错乱。
- 适用于广播和多播:UDP支持广播(将数据发送到网络中的所有主机)和多播(将数据发送到特定的一组主机)。
4. 异常处理
UDP虽然不需要建立连接,但客户端和服务器仍然可能遇到一些网络错误。可以使用try
/except
来捕获和处理异常。
import socket
def start_udp_server():
try:
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(('localhost', 12345))
print("UDP server is waiting for messages...")
while True:
data, client_address = server_socket.recvfrom(1024)
print(f"Received message from {client_address}: {data.decode()}")
server_socket.sendto(b"Hello, Client!", client_address)
except socket.error as e:
print(f"Socket error: {e}")
finally:
server_socket.close()
print("Server socket closed.")
if __name__ == "__main__":
start_udp_server()
在此代码中,try-except
用于捕获任何Socket错误,例如绑定失败或网络不可用等。
5. UDP与TCP的比较
特性 | UDP | TCP |
---|---|---|
连接类型 | 无连接 | 面向连接 |
可靠性 | 不可靠(可能丢包、重复、乱序) | 可靠(保证数据顺序和完整性) |
速度 | 快速 | 较慢(因有连接建立和确认机制) |
数据完整性 | 需要应用层保证 | 自动保证数据完整性和顺序 |
适用场景 | 实时通信(视频、音频、游戏等) | 文件传输、Web、电子邮件等应用 |
6. 总结
- UDP编程通过Python的
socket
模块实现相对简单,适用于不需要高可靠性的场景。 - UDP的优势在于快速传输,不需要建立连接,因此适合实时性要求高的应用场景,但其不保证数据传输的可靠性和顺序性。
- UDP的缺点是它不提供数据包的完整性、顺序保证以及错误检测,所以开发者需要自己处理丢包、数据重发等问题。
实例一,UDP的发送方
from socket import socket,AF_INET, SOCK_DGRAM
#1,创建socket对象
send_socket=socket(AF_INET,SOCK_DGRAM)
#2,准备发送数据
date=input('输入需要发送的数据')
#3,指定接收的IP和端口
ip_port=('127.0.0.1',8888)
#4,发送数据
send_socket.sendto(date.encode('utf-8'),ip_port)
#接收来自接收方的回复数据
recv_data,addr=send_socket.recvfrom(1024)
print('接收到的数据为:',recv_data.decode('utf-8'))
#5,关闭socketd对象
send_socket.close()
实例二,UDP的接收方
from socket import socket,AF_INET,SOCK_DGRAM
#1,创建socket对象
recv_socket=socket(AF_INET,SOCK_DGRAM)
#2,绑定IP地址和端口
recv_socket.bind(('127.0.0.1',8888))
#3,接收来自发送方的数据
recv_date,addr=recv_socket.recvfrom(1024)
print('接收到的数据:',recv_date.decode('utf-8'))
#4,准备回复对方的数据
date=input('请输入需要回复的数据')
#5,回复
recv_socket.sendto(date.encode('utf-8'),addr)
#6,关闭
recv_socket.close()
UDP编程接收方与发送方启动运行无先后,但先启动运行发送方,数据会丢包
实例三,模拟客服咨询小程序
客服端代码
from socket import socket,AF_INET,SOCK_DGRAM
#1,创建socket对象
recv_socket=socket(AF_INET,SOCK_DGRAM)
#2,绑定IP地址和端口
recv_socket.bind(('127.0.0.1',8888))
while True:
#3,接收发送过来的数据
recv_data,addr=recv_socket.recvfrom(1024)
print('客户说:',recv_data.decode('utf-8'))
if recv_data.decode('utf-8') =='bye':
break
#4,准备回复对方的数据
date=input('客服回:')
#5,发送
recv_socket.sendto(date.encode('utf-8'),addr)
#6,关闭socket对象
recv_socket.close()
咨询端代码
from socket import socket,AF_INET,SOCK_DGRAM
#1,创建socket对象
send_socket=socket(AF_INET,SOCK_DGRAM)
while True:
#2,准备发送的数据
date=input('客户说:')
#3,发送
send_socket.sendto(date.encode('utf-8'),('127.0.0.1',8888))
if date == 'bye':
break
#4,接收来自客服端的回复
recv_data,addr=send_socket.recvfrom(1024)
print('客服回:',recv_data.decode('utf-8'))
#5,关闭socket对象
send_socket.close()