pin_drop当前位置:知识文库 ❯ 图文

Socket编程基础 - Python网络编程入门教程

一、什么是Socket

Socket(套接字)是网络编程的核心概念,它是应用程序与网络协议栈之间的通信接口。可以把Socket想象为电话系统:Socket相当于电话机,IP地址是电话号码,而端口号则是分机号。

在Python中,我们使用内置的socket模块来创建和操作Socket,它提供了对底层网络通信的抽象,让开发者可以专注于业务逻辑而非网络细节。

小贴士

Socket概念起源于1983年加州大学伯克利分校发布的BSD Unix系统,后来成为POSIX标准的一部分。Python的socket模块是对C语言socket API的封装,保持了接口的一致性。

二、Python中的socket模块

Python的socket模块是标准库的一部分,无需额外安装即可使用。它支持多种地址族和套接字类型,是构建网络应用的基础工具。

导入socket模块

代码示例

import socket

# 创建TCP Socket(IPv4)
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 创建UDP Socket(IPv4)
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 创建IPv6 Socket
ipv6_socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)

常用Socket常量

  • socket.AF_INET:IPv4地址族

  • socket.AF_INET6:IPv6地址族

  • socket.SOCK_STREAM:TCP流式套接字

  • socket.SOCK_DGRAM:UDP数据报套接字

  • socket.SOCK_RAW:原始套接字

三、TCP与UDP协议对比

Socket编程主要涉及两种传输层协议:TCP和UDP。它们在网络通信中扮演着不同的角色,适用于不同的场景。

对比项 TCP UDP
连接方式 面向连接(三次握手) 无连接
可靠性 可靠传输,有确认机制 不可靠传输,不保证到达
传输速度 较慢(有额外开销) 快(无连接开销)
数据顺序 保证顺序 不保证顺序
应用场景 HTTP、FTP、SMTP等 视频直播、DNS、在线游戏
Python类型 SOCK_STREAM SOCK_DGRAM

四、地址族与套接字类型

在创建Socket时,需要指定地址族和套接字类型。地址族决定了使用IP协议版本,套接字类型决定了传输层协议。

地址族(Address Family)

地址族定义了网络地址的格式。最常用的是AF_INET(IPv4)和AF_INET6(IPv6)。IPv4地址格式为('127.0.0.1', 8080),而IPv6地址格式为('::1', 8080, 0, 0)

套接字类型(Socket Type)

套接字类型定义了数据传输的方式。TCP使用SOCK_STREAM提供字节流服务,UDP使用SOCK_DGRAM提供数据报服务。

代码示例

# 查看可用的地址族和套接字类型
import socket

print("可用的地址族:")
print(f"AF_INET: {socket.AF_INET}")
print(f"AF_INET6: {socket.AF_INET6}")

print("\n可用的套接字类型:")
print(f"SOCK_STREAM: {socket.SOCK_STREAM}")
print(f"SOCK_DGRAM: {socket.SOCK_DGRAM}")
print(f"SOCK_RAW: {socket.SOCK_RAW}")

五、Socket编程基本流程

无论是TCP还是UDP编程,Socket的生命周期都遵循一定的模式。了解这些流程有助于编写健壮的网络应用。

TCP Socket流程

  • 服务端:创建Socket → 绑定地址 → 监听连接 → 接受连接 → 收发数据 → 关闭连接

  • 客户端:创建Socket → 连接服务端 → 收发数据 → 关闭连接

UDP Socket流程

  • 接收方:创建Socket → 绑定地址 → 接收数据

  • 发送方:创建Socket → 发送数据(指定目标地址)

常用Socket方法

代码示例

# 常用Socket方法一览
import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 绑定地址(服务端)
sock.bind(('localhost', 8080))

# 监听连接(TCP服务端)
sock.listen(5)  # 最大等待连接数

# 接受连接(TCP服务端)
conn, addr = sock.accept()

# 连接服务器(TCP客户端)
sock.connect(('localhost', 8080))

# 发送数据
sock.send(b'Hello World')
sock.sendall(b'Complete message')  # 确保全部发送

# 接收数据
data = sock.recv(1024)

# UDP发送/接收
udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_sock.sendto(b'Hello', ('localhost', 8080))
data, addr = udp_sock.recvfrom(1024)

# 关闭Socket
sock.close()

六、完整代码示例

示例1:TCP回显服务器

下面是一个完整的TCP回显服务器示例,客户端发送的任何消息都会被原样返回。

代码示例

# tcp_echo_server.py - TCP回显服务器
import socket

def start_echo_server(host='localhost', port=8080):
    """启动TCP回显服务器"""
    # 创建TCP Socket
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_sock:
        # 设置SO_REUSEADDR,允许端口重用
        server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        
        # 绑定地址和端口
        server_sock.bind((host, port))
        
        # 开始监听
        server_sock.listen(5)
        print(f"服务器启动,监听 {host}:{port}")
        
        while True:
            # 等待客户端连接
            conn, addr = server_sock.accept()
            with conn:
                print(f"客户端已连接: {addr}")
                while True:
                    data = conn.recv(1024)
                    if not data:
                        break
                    print(f"收到: {data.decode('utf-8')}")
                    # 回显数据
                    conn.sendall(data)

if __name__ == '__main__':
    start_echo_server()

示例2:TCP客户端

代码示例

# tcp_echo_client.py - TCP回显客户端
import socket

def echo_client(message, host='localhost', port=8080):
    """连接到回显服务器并发送消息"""
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client_sock:
        # 连接服务器
        client_sock.connect((host, port))
        
        # 发送消息
        client_sock.sendall(message.encode('utf-8'))
        
        # 接收回显
        data = client_sock.recv(1024)
        print(f"服务器回显: {data.decode('utf-8')}")

if __name__ == '__main__':
    echo_client("Hello, Socket!")

示例3:UDP通信

代码示例

# udp_server.py - UDP服务器
import socket

def udp_server(host='localhost', port=9090):
    """UDP服务器"""
    with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as udp_sock:
        udp_sock.bind((host, port))
        print(f"UDP服务器启动,监听 {host}:{port}")
        
        while True:
            data, addr = udp_sock.recvfrom(1024)
            print(f"收到 {addr}: {data.decode('utf-8')}")
            # 发送响应
            udp_sock.sendto(b"Message received", addr)

# udp_client.py - UDP客户端
def udp_client(message, host='localhost', port=9090):
    """UDP客户端"""
    with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as udp_sock:
        udp_sock.sendto(message.encode('utf-8'), (host, port))
        response, addr = udp_sock.recvfrom(1024)
        print(f"服务器响应: {response.decode('utf-8')}")

七、注意事项

注意1:始终使用with语句管理Socket生命周期,确保连接正确关闭,避免资源泄漏。

注意2:TCP的send()不保证发送全部数据,建议使用sendall()确保完整发送。

注意3:服务端应设置SO_REUSEADDR选项,避免重启时报"Address already in use"错误。

注意4:处理网络数据时要注意异常处理,包括ConnectionResetErrorTimeoutError等网络异常。

八、小结与练习题

小结

  • Socket是网络通信接口:提供应用程序与网络协议栈之间的抽象层

  • TCP与UDP各有优势:TCP可靠有序,UDP快速高效

  • 正确使用资源管理:使用with语句或显式close()释放Socket资源

练习题

练习1

编写一个TCP聊天程序,支持多客户端同时连接,实现服务器端的消息转发功能。要求使用threading模块处理并发连接。

练习2

编写一个简单的文件传输工具,使用TCP协议实现客户端上传文件到服务器的功能。需要考虑大文件分块传输和传输完成的确认机制。

常见问题

Socket和HTTP有什么区别?

Socket是传输层的通信接口,属于底层API;HTTP是应用层协议,运行在TCP之上。HTTP请求实际上是通过Socket发送和接收数据的。Python的requests或urllib库底层就是使用Socket来实现HTTP通信的。

为什么TCP服务器需要listen()?

listen()将被动Socket转换为监听Socket,内核会维护一个连接队列来存储等待accept()的客户端连接。listen()参数指定了队列的最大长度,超过此长度的新连接会被拒绝。

如何选择TCP还是UDP?

如果需要可靠传输(如文件传输、网页浏览),选择TCP;如果能容忍少量数据丢失但要求低延迟(如视频直播、语音通话),选择UDP。大多数应用场景使用TCP即可满足需求。

recv()的缓冲区大小如何设置?

recv(n)的n参数指定一次最多接收的字节数。常用值为1024或4096。如果数据超过缓冲区,需要多次调用recv()。对于定长消息,可以使用固定缓冲区大小;对于变长消息,通常需要定义消息边界(如长度前缀或结束符)。

什么是SO_REUSEADDR?为什么需要它?

SO_REUSEADDR允许Socket绑定到一个处于TIME_WAIT状态的端口。当服务器异常关闭时,端口可能仍然被占用,设置此选项后可以立即重启服务器而不必等待端口释放(通常需要1-4分钟)。

标签: Socket 网络编程 TCP协议 UDP协议 Python教程

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: Python SQLAlchemy ORM教程 - 模型定义会话管理查询操作 下一篇: Python TCP客户端与服务端编程 - 网络通信实战教程

poll相关推荐