【python】python进阶——网络编程

目录

引言

[一、 网络编程基础](#一、 网络编程基础)

[1.1 什么是网络编程?](#1.1 什么是网络编程?)

[1.2 基本概念](#1.2 基本概念)

[二、 Socket编程](#二、 Socket编程)

[2.1 创建Socket](#2.1 创建Socket)

[2.2 TCP Socket工作流程](#2.2 TCP Socket工作流程)

[2.3 UDP Socket工作流程](#2.3 UDP Socket工作流程)

三、高级网络编程框架

[3.1 socketserver模块](#3.1 socketserver模块)

[3.2 异步网络编程](#3.2 异步网络编程)

四、简单的聊天应用实现

五、常见问题与解决方案

[5.1 端口占用问题](#5.1 端口占用问题)

[5.2 处理连接中断](#5.2 处理连接中断)

[5.3 设置超时](#5.3 设置超时)

附录:Python网络编程API参考

socket模块核心API

Socket对象方法

socketserver模块核心类

asyncio网络编程核心API

select模块核心API

常见常量参数


引言

网络编程是现代软件开发中不可或缺的一部分,而Python以其简洁的语法和强大的库支持,成为了网络编程的理想选择。

一、 网络编程基础

1.1 什么是网络编程?

网络编程是指编写能够在网络环境中运行的程序,这些程序可以跨越不同的设备进行通信和数据交换。

1.2 基本概念

  • IP地址:设备的网络标识

  • 端口:应用程序的通信端点(0-65535)

  • 协议:通信规则(TCP、UDP、HTTP等)

  • Socket:网络通信的基础接口

二、 Socket编程

Socket是网络编程的核心,提供了不同主机间进程通信的端点。

2.1 创建Socket

python 复制代码
import socket
​
# 创建TCP socket
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
​
# 创建UDP socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

参数说明:

  • AF_INET:IPv4地址族

  • SOCK_STREAM:TCP协议

  • SOCK_DGRAM:UDP协议

2.2 TCP Socket工作流程

服务器端:

python 复制代码
import socket
​
# 创建TCP socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
​
# 绑定地址和端口
server_socket.bind(('localhost', 8888))
​
# 开始监听
server_socket.listen(5)
print("服务器启动,等待连接...")
​
while True:
    # 接受客户端连接
    client_socket, addr = server_socket.accept()
    print(f"接收到来自 {addr} 的连接")
    
    # 接收数据
    data = client_socket.recv(1024)
    print(f"收到数据: {data.decode()}")
    
    # 发送响应
    client_socket.send("你好,客户端!".encode())
    
    # 关闭连接
    client_socket.close()

客户端:

python 复制代码
import socket
​
# 创建TCP socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
​
# 连接服务器
client_socket.connect(('localhost', 8888))
​
# 发送数据
client_socket.send("你好,服务器!".encode())
​
# 接收响应
response = client_socket.recv(1024)
print(f"服务器响应: {response.decode()}")
​
# 关闭连接
client_socket.close()

2.3 UDP Socket工作流程

服务器端:

python 复制代码
import socket
​
# 创建UDP socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
​
# 绑定地址和端口
udp_socket.bind(('localhost', 9999))
​
print("UDP服务器启动,等待数据...")
​
while True:
    # 接收数据
    data, addr = udp_socket.recvfrom(1024)
    print(f"收到来自 {addr} 的数据: {data.decode()}")
    
    # 发送响应
    udp_socket.sendto("收到消息!".encode(), addr)

客户端:

python 复制代码
import socket
​
# 创建UDP socket
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
​
# 发送数据
udp_socket.sendto("你好,UDP服务器!".encode(), ('localhost', 9999))
​
# 接收响应
response, addr = udp_socket.recvfrom(1024)
print(f"服务器响应: {response.decode()}")
​
# 关闭socket
udp_socket.close()

三、高级网络编程框架

3.1 socketserver模块

Python提供了更高级的socketserver模块,简化了网络服务器的创建。

TCP服务器示例:

python 复制代码
import socketserver
​
class MyTCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        # 处理请求
        self.data = self.request.recv(1024).strip()
        print(f"{self.client_address[0]} 发送: {self.data.decode()}")
        # 发送响应
        self.request.sendall(self.data.upper())
​
if __name__ == "__main__":
    HOST, PORT = "localhost", 9999
    
    # 创建TCP服务器
    with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
        print(f"服务器启动在 {HOST}:{PORT}")
        server.serve_forever()

3.2 异步网络编程

对于高性能网络应用,Python提供了asyncio模块。

异步TCP服务器示例:

python 复制代码
import asyncio
​
async def handle_client(reader, writer):
    data = await reader.read(100)
    message = data.decode()
    addr = writer.get_extra_info('peername')
    print(f"收到来自 {addr} 的消息: {message}")
    
    writer.write(f"已接收: {message}".encode())
    await writer.drain()
    
    writer.close()
​
async def main():
    server = await asyncio.start_server(
        handle_client, '127.0.0.1', 8888)
    
    addr = server.sockets[0].getsockname()
    print(f'服务器运行在 {addr}')
    
    async with server:
        await server.serve_forever()
​
asyncio.run(main())

四、简单的聊天应用实现

一个简单的多客户端聊天服务器示例:

python 复制代码
import socket
import threading
​
class ChatServer:
    def __init__(self, host='localhost', port=8888):
        self.host = host
        self.port = port
        self.clients = []
        self.nicknames = []
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    
    def broadcast(self, message):
        for client in self.clients:
            try:
                client.send(message)
            except:
                self.remove_client(client)
    
    def remove_client(self, client):
        if client in self.clients:
            index = self.clients.index(client)
            self.clients.remove(client)
            nickname = self.nicknames[index]
            self.nicknames.remove(nickname)
            self.broadcast(f"{nickname} 离开了聊天室!".encode())
    
    def handle_client(self, client):
        while True:
            try:
                message = client.recv(1024)
                self.broadcast(message)
            except:
                self.remove_client(client)
                break
    
    def receive(self):
        self.server_socket.bind((self.host, self.port))
        self.server_socket.listen()
        print(f"服务器运行在 {self.host}:{self.port}")
        
        while True:
            client, address = self.server_socket.accept()
            print(f"连接到: {str(address)}")
            
            client.send("NICK".encode())
            nickname = client.recv(1024).decode()
            
            self.nicknames.append(nickname)
            self.clients.append(client)
            
            print(f"用户昵称: {nickname}")
            self.broadcast(f"{nickname} 加入了聊天室!".encode())
            client.send("连接到服务器!".encode())
            
            thread = threading.Thread(target=self.handle_client, args=(client,))
            thread.start()
​
if __name__ == "__main__":
    server = ChatServer()
    server.receive()

五、常见问题与解决方案

5.1 端口占用问题

python 复制代码
# 设置SO_REUSEADDR选项解决端口占用
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

5.2 处理连接中断

python 复制代码
try:
    data = client_socket.recv(1024)
    if not data:
        print("连接已关闭")
        break
except ConnectionResetError:
    print("客户端连接中断")

5.3 设置超时

python 复制代码
# 设置接收超时
client_socket.settimeout(30.0)  # 30秒超时

附录:Python网络编程API参考

下面表格提供了Python网络编程中最常用API的完整参考,包括参数和返回值信息,可以帮助开发者更高效地使用Python进行网络编程。

socket模块核心API

API 描述 参数 返回值 示例
s.socket(family, type, proto) 创建新的socket对象 **family:**地址族(AF_INET/AF_INET6) type: socket类型(SOCK_STREAM/ SOCK_DGRAM) proto: 协议号(通常为0) socket对象 s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
s.gethostname() 获取当前主机名 字符串形式的主机名 host = socket.gethostname()
s.gethostbyname(hostname) 通过主机名获取IP地址 hostname: 主机名字符串 IP地址字符串 ip = socket.gethostbyname('www.example.com')
s.gethostbyaddr(ip_address) 通过IP地址获取主机信息 ip_address: IP地址字符串 (hostname, aliaslist, ipaddrlist)元组 info = socket.gethostbyaddr('8.8.8.8')
s.getservbyname(servicename, protocolname) 通过服务名获取端口号 servicename: 服务名称(如'http') protocolname: 协议名称(如'tcp') 端口号整数 port = socket.getservbyname('http', 'tcp')
s.getservbyport(port, protocolname) 通过端口号获取服务名 port: 端口号整数 protocolname: 协议名称(如'tcp') 服务名字符串 service = socket.getservbyport(80, 'tcp')
s.inet_aton(ip_string) 将IPv4地址转换为32位打包二进制格式 ip_string: IPv4地址字符串 打包的二进制数据(4字节) packed = socket.inet_aton('192.168.1.1')
s.inet_ntoa(packed_ip) 将32位打包的IPv4地址转换为字符串格式 packed_ip: 打包的二进制IP地址 IPv4地址字符串 ip = socket.inet_ntoa(packed)
s.inet_pton(address_family, ip_str) 将IP地址转换为打包二进制格式 address_family: AF_INET或AF_INET6 ip_str: IP地址字符串 打包的二进制数据 packed = socket.inet_pton(socket.AF_INET6, '::1')
s.inet_ntop(address_family, packed_ip) 将打包的二进制IP地址转换为字符串格式 address_family: AF_INET或AF_INET6 packed_ip: 打包的 二进制IP地址 IP地址字符串 ip=socket.inet_ntop (socket.AF_INET6, packed)

Socket对象方法

方法 描述 参数 返回值 适用协议
bind(address) 将socket绑定到地址 address: (host, port)元组 TCP/UDP
listen(backlog) 启动TCP监听 backlog: 最大挂起连接数 TCP
accept() 接受TCP连接 (socket, address)元组 TCP
connect(address) 连接到远程socket address: (host, port)元组 TCP
connect_ex(address) connect()的扩展版本,出错时返回错误码而非异常 address: (host, port)元组 错误代码(成功时为0) TCP
send(data) 发送TCP数据 data: 要发送的字节数据 已发送的字节数 TCP
recv(bufsize) 接收TCP数据 bufsize: 最大接收字节数 接收到的数据字节 TCP
sendall(data) 完整发送TCP数据 data: 要发送的字节数据 无(成功)/抛出异常(失败) TCP
sendto(data, address) 发送UDP数据 data: 要发送的字节数据 address: (host, port)元组 已发送的字节数 UDP
recvfrom(bufsize) 接收UDP数据 bufsize: 最大接收字节数 (data, address)元组 UDP
close() 关闭socket TCP/UDP
settimeout(value) 设置超时时间(秒) value: 超时时间(浮点数) TCP/UDP
gettimeout() 获取超时设置 超时时间(秒), 未设置返回None TCP/UDP
setsockopt(level, optname, value) 设置socket选项 level: 选项级别 optname: 选项名称 value: 选项值 TCP/UDP
getsockopt(level, optname) 获取socket选项 level: 选项级别 optname: 选项名称 选项值 TCP/UDP
setblocking(flag) 设置阻塞或非阻塞模式 flag: True为阻塞, False为非阻塞 TCP/UDP
getpeername() 返回远程地址 (ip, port)元组 TCP
getsockname() 返回socket自己的地址 (ip, port)元组 TCP/UDP
shutdown(how) 关闭连接的一部分 how: SHUT_RD/ SHUT_WR/ SHUT_RDWR TCP

socketserver模块核心类

描述 主要方法 返回值
server.TCPServer TCP同步服务器基类 serve_forever(): 持续处理请求 handle_request(): 处理单个请求 shutdown(): 停止服务
server.UDPServer UDP同步服务器基类 同上 同上
server.ThreadingMixIn 线程混合类,用于创建多线程服务器 与服务器类混合使用
server.ForkingMixIn 进程混合类,用于创建多进程服务器 与服务器类混合使用
server.BaseRequestHandler 请求处理程序基类 handle(): 必须重写的方法,处理请求 setup(): 初始化方法 finish(): 清理方法

asyncio网络编程核心API

API 描述 参数 返回值
asyncio.start_server(client_connected_cb, host, port) 创建TCP服务器 client_connected_cb: 客户端连接回调 host: 主机地址 port: 端口号 Server对象
asyncio.open_connection(host, port) 创建TCP客户端连接 host: 服务器主机地址 port: 服务器端口号 (reader, writer)元组
asyncio.start_unix_server(client_connected_cb, path) 创建Unix域套接字服务器 client_connected_cb: 客户端连接回调 path: 套接字路径 Server对象
asyncio.open_unix_connection(path) 创建Unix域套接字客户端连接 path: 套接字路径 (reader, writer)元组
asyncio.StreamReader.read(n) 从流中读取数据 n: 要读取的字节数 读取的数据(bytes)
asyncio.StreamReader.readline() 从流中读取一行 读取的行(bytes)
asyncio.StreamWriter.write(data) 向流中写入数据 data: 要写入的数据(bytes)
asyncio.StreamWriter.drain() 等待写入操作完成
asyncio.StreamWriter.close() 关闭流

select模块核心API

API 描述 参数 返回值
select.select(rlist, wlist, xlist[, timeout]) 等待I/O就绪 rlist: 等待读取的对象列表 wlist: 等待写入的对象列表 xlist: 等待异常的对象列表 timeout: 超时时间(秒) (rready, wready, xready)三元组
select.poll() 创建poll对象 poll对象
poll.register(fd[, eventmask]) 注册文件描述符到poll对象 fd: 文件描述符 eventmask: 事件掩码
poll.unregister(fd) 从poll对象中取消注册文件描述符 fd: 文件描述符
poll.poll([timeout]) 等待事件 timeout: 超时时间(毫秒) [(fd, event), ...]列表

常见常量参数

常量 描述
socket.AF_INET 2 IPv4地址族
socket.AF_INET6 10 IPv6地址族
socket.SOCK_STREAM 1 TCP协议类型
socket.SOCK_DGRAM 2 UDP协议类型
socket.SOL_SOCKET 1 Socket选项级别
socket.SO_REUSEADDR 2 地址重用选项
socket.SO_KEEPALIVE 9 保持连接选项
socket.SHUT_RD 0 关闭接收方向
socket.SHUT_WR 1 关闭发送方向
socket.SHUT_RDWR 2 关闭双向连接

参考

相关推荐
kyle-fang1 小时前
阿里云服务器部署MySQL
服务器·mysql·阿里云
开开心心_Every1 小时前
Win10/Win11版本一键切换工具
linux·运维·服务器·edge·pdf·web3·共识算法
啟明起鸣1 小时前
【Nginx 网关开发】从源码分析 Nginx 的多进程启动原理
运维·nginx
怣501 小时前
Linux创意命令组合:让终端变得有趣又高效
linux·运维·服务器
啟明起鸣2 小时前
【Nginx 网关开发】上手 Nginx,简简单单启动一个静态 html 页面
运维·c语言·前端·nginx·html
未来之窗软件服务2 小时前
自己平台接入国家网络身份认证公共服务接入
网络·仙盟创梦ide·东方仙盟
lisanmengmeng2 小时前
添加ceph节点
linux·服务器·ceph
Tinyundg2 小时前
Linux系统分区
linux·运维·服务器
要做一个小太阳2 小时前
华为Atlas 900 A3 SuperPoD 超节点网络架构
运维·服务器·网络·华为·架构
江畔何人初2 小时前
service发现
linux·运维·云原生