跳至内容

Socket 编程

socket 是 Python 标准库中进行网络通信的底层模块。所有高层网络库(httpasyncioaiohttp 等)都基于 socket 实现。

Socket 基本函数

函数说明
socket.socket(family, type)创建套接字。AF_INET=IPv4,SOCK_STREAM=TCP,SOCK_DGRAM=UDP
s.bind((host, port))绑定地址和端口(服务端)
s.listen(backlog)开始监听,backlog 为等待队列长度
s.accept()阻塞,等待客户端连接,返回 (conn, addr)
s.connect((host, port))连接服务端(客户端)
s.send(data)发送字节数据
s.recv(bufsize)接收最多 bufsize 字节
s.close()关闭套接字
s.setsockopt(level, option, value)设置套接字选项
s.settimeout(seconds)设置超时时间

TCP 通信示例

TCP 是可靠的面向连接协议,通信前需要三次握手建立连接。

TCP 服务端

import socket

def run_server(host: str = "127.0.0.1", port: int = 9000) -> None:
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # SO_REUSEADDR:允许重用端口,避免 TIME_WAIT 状态导致的"端口占用"错误
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    server.bind((host, port))
    server.listen(5)
    print(f"服务器监听 {host}:{port}")

    while True:
        conn, addr = server.accept()   # 阻塞,等待新连接
        print(f"客户端连接: {addr}")

        try:
            while True:
                data = conn.recv(1024)
                if not data:
                    break   # 客户端断开连接

                message = data.decode("utf-8")
                print(f"收到: {message}")

                reply = f"服务端已收到: {message}"
                conn.sendall(reply.encode("utf-8"))
        finally:
            conn.close()
            print(f"客户端 {addr} 断开")

if __name__ == "__main__":
    run_server()

TCP 客户端

import socket

def run_client(host: str = "127.0.0.1", port: int = 9000) -> None:
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
        client.connect((host, port))
        print(f"已连接到 {host}:{port}")

        messages = ["Hello!", "Python socket", "再见"]
        for msg in messages:
            client.sendall(msg.encode("utf-8"))
            data = client.recv(1024)
            print(f"服务端回复: {data.decode('utf-8')}")

if __name__ == "__main__":
    run_client()

处理多客户端(多线程)

单进程服务器每次只能处理一个客户端,使用多线程可并发处理多个连接:

import socket
import threading

def handle_client(conn: socket.socket, addr: tuple) -> None:
    print(f"新连接: {addr}")
    try:
        while True:
            data = conn.recv(1024)
            if not data:
                break
            conn.sendall(data)   # echo server:原样返回
    finally:
        conn.close()

def run_echo_server(host: str = "0.0.0.0", port: int = 9001) -> None:
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
        server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server.bind((host, port))
        server.listen(10)
        print(f"Echo 服务器启动 {host}:{port}")

        while True:
            conn, addr = server.accept()
            t = threading.Thread(target=handle_client, args=(conn, addr), daemon=True)
            t.start()

if __name__ == "__main__":
    run_echo_server()

UDP 通信示例

UDP 无连接,不保证送达,但速度快,适合实时场景(视频流、游戏等)。

UDP 服务端

import socket

def run_udp_server(host: str = "127.0.0.1", port: int = 9002) -> None:
    with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as server:
        server.bind((host, port))
        print(f"UDP 服务器监听 {host}:{port}")

        while True:
            data, addr = server.recvfrom(1024)   # 同时返回数据和来源地址
            print(f"来自 {addr}: {data.decode()}")

            reply = f"已收到: {data.decode()}"
            server.sendto(reply.encode(), addr)

if __name__ == "__main__":
    run_udp_server()

UDP 客户端

import socket

def run_udp_client(host: str = "127.0.0.1", port: int = 9002) -> None:
    with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as client:
        client.settimeout(5)   # 超时 5 秒

        for msg in ["Hello", "World"]:
            client.sendto(msg.encode(), (host, port))
            try:
                reply, server_addr = client.recvfrom(1024)
                print(f"服务端回复: {reply.decode()}")
            except socket.timeout:
                print("等待回复超时")

if __name__ == "__main__":
    run_udp_client()

超时与非阻塞

import socket

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(("127.0.0.1", 9003))
server.listen(5)

# 设置 accept 超时时间
server.settimeout(10)

try:
    conn, addr = server.accept()
    print(f"连接: {addr}")
except socket.timeout:
    print("10 秒内无客户端连接,退出")
finally:
    server.close()

获取本机信息

import socket

hostname = socket.gethostname()
local_ip = socket.gethostbyname(hostname)
print(f"主机名: {hostname}")
print(f"本机 IP: {local_ip}")

# 查询远程主机 IP
remote_ip = socket.gethostbyname("www.python.org")
print(f"python.org IP: {remote_ip}")
最后更新于