Python 网络编程:Socket、TCP、UDP、HTTP 服务器实战

小飞兽 Python 5 次阅读 2026-07-24

Introduction

Socket 是网络编程的基础。本文从 TCP/UDP 基础讲起,搭建简单的 TCP 多客户端聊天服务器、实现 HTTP 服务器、以及使用 asyncio 实现异步网络编程。

---

Socket 基础

import socket

# TCP 服务器
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('0.0.0.0', 9999))
server.listen(5)
print('TCP 服务器监听 :9999')

while True:
    client, addr = server.accept()
    print(f'客户端连接: {addr}')
    data = client.recv(1024)
    client.sendall(b'Hello, ' + data)
    client.close()
# TCP 客户端
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('localhost', 9999))
client.sendall(b'World')
response = client.recv(1024)
print('收到:', response.decode())
client.close()

TCP 多客户端聊天服务器

import socket, threading

clients = []

def broadcast(message, sender=None):
    for client in clients:
        if client != sender:
            try:
                client.sendall(message)
            except:
                clients.remove(client)

def handle_client(client):
    while True:
        try:
            data = client.recv(1024)
            if not data:
                break
            broadcast(data, sender=client)
        except:
            clients.remove(client)
            client.close()
            break

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(('0.0.0.0', 9999))
server.listen()
print('聊天室服务器已启动')

while True:
    client, addr = server.accept()
    clients.append(client)
    thread = threading.Thread(target=handle_client, args=(client,))
    thread.daemon = True
    thread.start()

UDP 服务器

import socket

server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind(('0.0.0.0', 9999))
print('UDP 服务器监听 :9999')

while True:
    data, addr = server.recvfrom(1024)
    print(f'收到 {addr}: {data.decode()}')
    server.sendto(b'ACK: ' + data, addr)

HTTP 服务器

from http.server import HTTPServer, BaseHTTPRequestHandler
import json

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(200)
            self.send_header('Content-type', 'text/html; charset=utf-8')
            self.end_headers()
            self.wfile.write(b'<h1>Hello from Python HTTP Server</h1>')
        elif self.path == '/api/status':
            self.send_response(200)
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            self.wfile.write(json.dumps({'status': 'ok', 'clients': 5}).encode())
        else:
            self.send_error(404)

HTTPServer(('0.0.0.0', 8080), Handler).serve_forever()

asyncio 异步网络编程

import asyncio

async def handle_client(reader, writer):
    addr = writer.get_extra_info('peername')
    print(f'客户端连接: {addr}')
    
    while True:
        data = await reader.read(1024)
        if not data:
            break
        writer.write(data)  # 回显
        await writer.drain()
    
    print(f'客户端断开: {addr}')
    writer.close()
    await writer.wait_closed()

async def main():
    server = await asyncio.start_server(
        handle_client, '0.0.0.0', 9999
    )
    print('异步服务器监听 :9999')
    async with server:
        await server.serve_forever()

asyncio.run(main())

常见问题

Q1: socket.AF_INET 和 SOCK_STREAM 什么意思?AF_INET 表示 IPv4,SOCK_STREAM 是 TCP(面向连接);SOCK_DGRAM 是 UDP(无连接)。

Q2: 为什么服务器要 setSocketOpt(SO_REUSEADDR)? 防止程序崩溃后端口被占用处于 TIME_WAIT 状态,设置为 1 可以立即重用端口。

Q3: asyncio 比 threading 好在哪?asyncio 是单线程协程,切换开销远小于线程,适合大量并发 I/O 连接场景(如聊天服务器、爬虫)。

延伸阅读

  • Python asyncio 进阶
  • WebSocket 实时通信
  • HTTP/2 和 HTTP/3

---

作者:小马 | 绍大技术网 shaoda.net