在当今的网络世界中,Socket编程是构建网络通信应用的关键技术之一。从简单的聊天应用到复杂的分布式系统,Socket编程都扮演着至关重要的角色。本文将首先介绍Socket编程的基本原理,然后详细讲解如何使用Python进行Socket编程。
注意:文中谈到的TCP/IP协议可以去我另一篇文章看一下,本文主要讲我们怎么进行socket编程。
一、Socket编程原理
Socket编程是一种网络通信的API,它提供了跨平台、跨语言的网络通信能力。Socket编程接口实际上是一个广泛的编程接口,可以用于多种协议,包括TCP、UDP以及其他更底层的协议(如原始套接字用于IP层通信)。但是在大多数应用中,TCP和UDP是最常用的协议(因为它们提供了网络编程所需的基本特性),所以本文主要讲TCP Socket 编程和UDP Socket 编程。
TCP Socket 编程
当我们在使用Socket API进行编程时,我们写的代码实际上是在与TCP/IP协议栈进行交互。
具体流程如下:
- 创建Socket:当您创建一个Socket对象时,您实际上是在请求TCP/IP协议栈分配一个唯一的套接字标识符(socket ID)和相关的资源。
- 绑定地址:绑定操作告诉TCP/IP协议栈,您希望将哪个IP地址和端口号与您的Socket关联起来。这样,当远程主机尝试连接到您的Socket时,TCP/IP协议栈就知道如何处理这个连接请求。
- 监听连接:服务器端Socket的监听操作告诉TCP/IP协议栈,它应该接受来自客户端的连接请求。当有客户端发起连接时,TCP/IP协议栈会处理底层的连接建立过程,并通知您的代码连接已经建立。
- 数据交换:当您使用Socket发送或接收数据时,您的代码实际上是在将数据传递给TCP/IP协议栈,或者从TCP/IP协议栈接收数据。TCP/IP协议栈负责将数据打包成适当的格式(例如,TCP数据包或UDP数据报),并将其发送到目标主机。同样,当TCP/IP协议栈接收到来自远程主机的数据时,它会将数据传递给与Socket关联的代码。
- 关闭连接:当您关闭Socket连接时,您的代码实际上是在告诉TCP/IP协议栈释放与该连接关联的所有资源。TCP/IP协议栈会负责完成底层的连接关闭过程。
UDP Socket 编程
当使用Socket进行UDP(用户数据报协议)通信时,原理与TCP通信有所不同,因为UDP是一个无连接、不可靠的传输协议。
具体流程如下:
- 创建Socket:
在通信的两端(客户端和服务器),都需要创建一个UDP Socket对象。这个对象将负责UDP通信的相关操作。 - 绑定地址(可选):
对于服务器端Socket,通常也需要绑定到一个具体的IP地址和端口号上,以便客户端能够找到它。但需要注意的是,UDP的绑定是可选的,如果服务器端不绑定到特定端口,那么操作系统会为其选择一个可用的临时端口。
客户端Socket则不需要绑定,因为UDP是无连接的,客户端只需要知道服务器的IP地址和端口号就可以发送数据报。 - 发送数据报:
客户端使用UDP Socket的sendto
方法向服务器发送数据报。在发送时,需要指定目标服务器的IP地址和端口号。
服务器使用UDP Socket的recvfrom
方法来接收来自客户端的数据报。这个方法会返回发送方的IP地址和端口号,以及接收到的数据内容。 - 数据交换:
UDP通信中,数据以数据报的形式发送和接收。每个数据报都是独立的,不依赖于之前的或之后的数据报。
UDP不提供像TCP那样的流控制、错误检查和顺序保证。这意味着数据报可能会丢失、乱序或重复到达。因此,在UDP通信中,应用程序需要负责处理这些问题。 - 关闭连接:
与TCP不同,UDP没有显式的连接建立和关闭过程。当数据报发送或接收完成后,Socket对象通常可以继续使用,或者可以被销毁以释放资源。 - 广播和多播:
UDP还支持广播和多播功能。广播是指向本地网络上的所有主机发送数据报,而多播则是向一组特定的主机(属于同一个多播组)发送数据报。这些功能在需要向多个接收者发送相同数据的情况下非常有用。 - 缓冲区管理:
UDP Socket有一个接收缓冲区来存储接收到的数据报。如果应用程序没有及时读取接收缓冲区中的数据,那么新的数据报可能会覆盖旧的数据报(取决于缓冲区的大小和配置)。因此,在使用UDP时,应用程序需要确保及时读取接收到的数据报。
二、Python Socket编程实践
Python提供了丰富的Socket编程库,使得开发者可以轻松地实现网络通信功能。
基于TCP协议的Python socket编程
TCP 服务器
import socket
def tcp_server():
# 创建一个TCP/IP socket
# 参数 AF_INET 表示该socket网络层使用IP协议
# 参数 SOCK_STREAM 表示该socket传输层使用TCP协议
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定到地址和端口
server_address = ('localhost', 12345)
sock.bind(server_address)
# 监听连接,等待客户端的连接请求
# 最多接受2个等待连接的客户端
sock.listen(2)
print('等待连接...')
connection, client_address = sock.accept()
print(f"接受一个客户端连接 {client_address}")
# 接收数据并返回
while True:
# 指定从接收缓冲里最多读取100个字节
recv_data = connection.recv(100) # 返回的数据是bytes类型的,需要用decode()解码
print(f"收到信息: {recv_data.decode()}")
if recv_data.decode() == "退出":
break
send_data = input("输入发送给客户端的数据: ")
connection.send(send_data.encode()) # 发送的数据也是bytes类型的,所以这里需要encode()编码
if send_data == "退出":
break
connection.close()
sock.close()
if __name__ == '__main__':
tcp_server()
TCP 客户端
import socket
def tcp_client():
# 创建一个TCP/IP socket
# 参数 AF_INET 表示该socket网络层使用IP协议
# 参数 SOCK_STREAM 表示该socket传输层使用TCP协议
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接到服务器
server_address = ('localhost', 12345)
sock.connect(server_address)
while True:
# 发送数据
# send_data = b'123'
send_data = input("输入发送的数据: ")
sock.send(send_data.encode())
if send_data == "退出":
break
# 接收数据
recv_data = sock.recv(100)
print(f"接收到的数据 {recv_data.decode()}")
if recv_data.decode() == "退出":
break
sock.close()
if __name__ == '__main__':
tcp_client()
基于UDP协议的Python socket编程
UDP 服务器
import socket
def udp_server():
# 创建一个UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定到地址和端口
server_address = ('localhost', 12345)
sock.bind(server_address)
while True:
# 接收数据
# print('等待接收数据...')
recv_data, address = sock.recvfrom(4096)
print(f"地址: {address} 数据: {recv_data.decode()}")
if recv_data.decode() == "退出":
break
# 发送数据
send_data = input("请输入要发送的数据: ")
sent = sock.sendto(send_data.encode(), address)
print(f"向{address}发送{sent}字节")
if send_data == "退出":
break
sock.close()
if __name__ == '__main__':
udp_server()
UDP 客户端
import socket
def udp_client():
# 创建一个UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 服务器地址和端口
server_address = ('localhost', 12345)
while True:
# 发送数据
# send_data = b'123' # 这种方式是不能写中文的,所以还是建议用encode()
send_data = input("请输入要发送的数据: ")
sent = sock.sendto(send_data.encode(), server_address)
# 接收数据
# print('等待接收数据...')
recv_data, server = sock.recvfrom(4096)
print(f"地址: {server} 数据: {recv_data.decode()}")
if recv_data.decode() == "退出":
break
sock.close()
if __name__ == '__main__':
udp_client()
标签:UDP,Socket,Python,编程,sock,TCP,data,socket
From: https://blog.csdn.net/qq_64192931/article/details/139442726