0

0

如何用Python进行网络编程(Socket)?

狼影

狼影

发布时间:2025-09-04 17:28:01

|

371人浏览过

|

来源于php中文网

原创

Python Socket编程中TCP与UDP的核心差异在于:TCP是面向连接、可靠的协议,适用于文件传输等需数据完整性的场景;UDP无连接、速度快,适合实时音视频、游戏等对延迟敏感的应用。选择依据是对可靠性与速度的需求权衡。

如何用python进行网络编程(socket)?

使用Python进行网络编程,核心在于其内置的

socket
模块。它提供了一套标准接口,让程序能够像打电话一样,通过IP地址和端口号与其他程序建立连接,进行数据交换。无论是构建一个简单的聊天客户端,还是复杂的服务器应用,我们都是围绕着创建socket、绑定/连接、监听/发送/接收这些基本操作来展开的。这不仅仅是技术细节,更是一种通信思维的体现,让不同的程序能够在网络空间中“对话”。

解决方案

Python的

socket
模块是进行网络编程的基石。这里我将通过一个简单的TCP客户端和服务器的例子,来展示其基本用法。

服务器端代码示例:

import socket
import threading # 后面会提到多线程,这里先引入

HOST = '127.0.0.1'  # 服务器监听的IP地址
PORT = 65432        # 服务器监听的端口

def handle_client(conn, addr):
    """处理单个客户端连接的函数"""
    print(f"Connected by {addr}")
    try:
        while True:
            data = conn.recv(1024) # 接收客户端数据,最大1024字节
            if not data: # 如果没有数据,说明客户端断开连接
                print(f"Client {addr} disconnected.")
                break
            message = data.decode('utf-8')
            print(f"Received from {addr}: {message}")

            # 回复客户端
            response = f"Server received: {message}"
            conn.sendall(response.encode('utf-8'))
    except ConnectionResetError:
        print(f"Client {addr} forcibly closed the connection.")
    except Exception as e:
        print(f"Error handling client {addr}: {e}")
    finally:
        conn.close() # 关闭客户端连接

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT)) # 绑定IP地址和端口
    s.listen() # 开始监听,等待客户端连接
    print(f"Server listening on {HOST}:{PORT}")

    while True:
        conn, addr = s.accept() # 接受新的客户端连接
        # 为每个新连接创建一个线程来处理,避免阻塞主进程
        client_thread = threading.Thread(target=handle_client, args=(conn, addr))
        client_thread.start()

客户端代码示例:

立即学习Python免费学习笔记(深入)”;

import socket

HOST = '127.0.0.1'  # 服务器的IP地址
PORT = 65432        # 服务器的端口

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    try:
        s.connect((HOST, PORT)) # 连接到服务器
        print(f"Connected to {HOST}:{PORT}")

        message_to_send = "Hello, server! This is client."
        s.sendall(message_to_send.encode('utf-8')) # 发送数据

        data = s.recv(1024) # 接收服务器的回复
        print(f"Received from server: {data.decode('utf-8')}")

    except ConnectionRefusedError:
        print("Connection refused. Is the server running?")
    except Exception as e:
        print(f"An error occurred: {e}")
    finally:
        print("Client closing connection.")
        # s.close() # with 语句块结束时会自动关闭

在这些例子中,

socket.AF_INET
指定了使用IPv4地址族,
socket.SOCK_STREAM
则表示使用TCP协议(流式套接字)。服务器通过
bind()
绑定地址,
listen()
开始监听,然后
accept()
接受连接。每个
accept()
返回一个新的套接字对象
conn
,用于与特定客户端通信,以及客户端的地址
addr
。客户端则直接使用
connect()
连接服务器。数据传输时,需要注意字符串和字节串之间的编码(
encode()
)和解码(
decode()
)。

Python Socket编程中TCP与UDP的选择与核心差异是什么?

在Python的Socket编程中,我们通常会选择TCP(传输控制协议)或UDP(用户数据报协议)。这两种协议各有优劣,选择哪一个往往取决于你的应用场景对数据可靠性和传输速度的需求。

TCP (Transmission Control Protocol) TCP是一种面向连接的协议。这意味着在数据传输之前,客户端和服务器之间必须先建立一个可靠的连接。它提供:

  • 可靠性: TCP确保数据能够无差错、按顺序地到达目的地。如果数据包丢失或损坏,TCP会自动重传。
  • 有序性: 数据会按照发送的顺序接收。
  • 流量控制: 防止发送方发送数据过快,导致接收方无法处理。
  • 拥塞控制: 避免网络过载。

何时选择TCP? 我个人在开发需要高度数据完整性的应用时,比如文件传输、网页浏览(HTTP)、电子邮件(SMTP/POP3/IMAP)或数据库连接时,总是优先考虑TCP。它的可靠性省去了很多手动处理数据丢失和乱序的麻烦,虽然会带来一些额外的开销和延迟,但这种“省心”的特性对于大多数业务应用来说是值得的。

在Python中,创建TCP Socket使用

socket.socket(socket.AF_INET, socket.SOCK_STREAM)

UDP (User Datagram Protocol) UDP是一种无连接的协议。它不保证数据的可靠传输,也不保证数据包的顺序。每个UDP数据报都是一个独立的单元,发送后就“不管不顾”了。

  • 不可靠性: 数据包可能丢失、重复或乱序。
  • 无序性: 接收到的数据包顺序可能与发送顺序不同。
  • 速度快: 由于没有建立连接的握手过程,也没有重传、流量控制等机制,UDP的传输速度通常比TCP快。
  • 开销小: 头部信息比TCP小,对系统资源占用少。

何时选择UDP? 对于那些对实时性要求极高,但可以容忍少量数据丢失的应用,UDP是更好的选择。比如在线游戏、实时音视频流(VoIP)、DNS查询等。在这种场景下,如果一个数据包丢失了,重传它反而会增加延迟,不如直接发送下一个数据包,让应用层去处理可能的“瑕疵”。在我看来,如果你需要自己实现复杂的可靠性机制,或者对延迟有极致要求,才会考虑UDP。

在Python中,创建UDP Socket使用

socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
。UDP的发送和接收方法也不同,它使用
sendto()
recvfrom()
,因为每次发送都需要指定目标地址,接收时也会返回发送方的地址。

总结来说,TCP是“严谨的信使”,确保每一封信都准确无误、按时送达;UDP则是“快速的广播员”,信息发出去就不管了,谁收到算谁的,但速度绝对快。根据你对“信息”的重视程度,做出合适的选择。

如何处理Python Socket编程中的常见错误和异常?

在Python Socket编程中,网络环境的复杂性和不可预测性意味着错误和异常是常态。不恰当的错误处理轻则导致程序崩溃,重则引发数据丢失或安全问题。我的经验是,预见并妥善处理这些异常,是构建健壮网络应用的关键。

以下是一些常见的Socket错误和它们的处理策略:

  1. ConnectionRefusedError
    (连接被拒绝):

    • 场景: 客户端尝试连接一个不存在的服务器、服务器未启动、或者服务器防火墙阻止了连接。
    • 处理: 在客户端的
      connect()
      调用周围使用
      try...except ConnectionRefusedError:
      捕获。可以尝试重试连接,或者向用户显示错误信息。
  2. ConnectionResetError
    (连接被重置):

    • 场景: 通常发生在服务器端,当客户端在没有正常关闭连接的情况下突然断开(例如,客户端程序崩溃、网络中断)。服务器尝试向已关闭的连接写入或读取时会触发。
    • 处理: 在服务器的
      recv()
      send()
      循环中捕获此异常。一旦捕获,意味着客户端已断开,应该关闭对应的客户端socket并清理资源。
  3. BrokenPipeError
    (管道破裂):

    Rose.ai
    Rose.ai

    一个云数据平台,帮助用户发现、可视化数据

    下载
    • 场景: 当你试图向一个已经关闭的socket写入数据时,会抛出此错误。它与
      ConnectionResetError
      有些相似,但通常发生在尝试
      send()
      时。
    • 处理: 类似
      ConnectionResetError
      ,在发送数据前检查连接状态,或者在
      send()
      调用周围捕获。一旦发生,说明连接已不可用。
  4. TimeoutError
    (超时错误):

    • 场景: 当socket操作(如
      connect()
      ,
      recv()
      ,
      send()
      ,
      accept()
      ) 在指定时间内没有完成时发生。
    • 处理: 可以通过
      socket.settimeout(seconds)
      方法为socket设置一个超时时间。在
      try...except TimeoutError:
      中捕获,然后决定是重试、跳过还是报告错误。这对于防止程序长时间阻塞在网络操作上非常重要。
  5. BlockingIOError
    (阻塞IO错误):

    • 场景: 当socket设置为非阻塞模式(
      socket.setblocking(False)
      )后,如果一个操作(如
      recv()
      )会阻塞,就会立即抛出此错误。
    • 处理: 这不是一个真正的错误,而是非阻塞模式下的一种预期行为。通常与
      select
      selectors
      asyncio
      等异步I/O机制结合使用,表示当前没有数据可读或不可写,需要稍后再试。
  6. OSError
    (操作系统错误):

    • 场景: 这是一个更通用的错误,
      socket.error
      在Python 3.3+中被
      OSError
      取代。它可能包含上述所有特定错误,也可能包含其他系统级别的网络错误,例如“地址已被使用”(
      Address already in use
      )当服务器尝试绑定一个已被占用的端口时。
    • 处理: 对于“地址已被使用”错误,可以尝试更改端口,或者在服务器关闭后等待一段时间再启动。对于其他通用的
      OSError
      ,通常需要查看其错误码或错误信息以进行具体判断。

通用处理策略:

  • 使用
    try...except
    块:
    这是Python处理异常的基本方式。将所有可能抛出异常的网络操作放入
    try
    块中,并在
    except
    块中处理。
  • finally
    块:
    确保在
    finally
    块中关闭socket连接和释放资源,无论是否发生异常。
    with socket.socket(...) as s:
    语句在Python 3中是更好的实践,它能自动管理socket的关闭。
  • 日志记录: 记录捕获到的异常信息,包括时间、错误类型、错误消息和相关上下文,这对于调试和问题排查至关重要。
  • 优雅关闭: 在关闭socket之前,尝试使用
    socket.shutdown(socket.SHUT_RDWR)
    来通知对端不再发送或接收数据,这有助于更优雅地断开连接。

记住,网络是不可靠的。与其期望一切顺利,不如假设一切都会出错,并为每一种可能的情况做好准备。这虽然增加了代码的复杂度,但大大提升了程序的健壮性和用户体验。

Python Socket服务器如何实现多客户端并发连接?

一个基本的Python Socket服务器,如果不做特殊处理,一次只能处理一个客户端连接。当它在

conn.recv()
conn.send()
上阻塞时,其他等待连接的客户端就只能排队。这显然无法满足现代网络应用的需求。实现多客户端并发连接,是构建实用网络服务的必经之路。

有几种主流的方法可以解决这个问题,每种方法都有其适用场景和权衡:

  1. 多线程(Threading)

    • 原理: 每当服务器接受到一个新的客户端连接(
      s.accept()
      ),就创建一个新的线程来处理这个客户端的通信。主线程继续监听新的连接。
    • 优点: 实现相对简单直观,每个客户端的处理逻辑可以独立编写。对于I/O密集型任务(即大部分时间在等待网络数据),Python的GIL(全局解释器锁)影响不大,因为线程在等待I/O时会释放GIL。
    • 缺点: 线程的创建和管理有一定开销。对于CPU密集型任务,由于GIL的存在,多线程并不能真正实现并行计算,只是并发执行。线程之间的共享数据需要加锁保护,否则可能出现竞态条件。
    • 适用场景: 中小型服务器应用,I/O操作较多,对CPU计算要求不高的场景。

    我的示例代码中已经包含了多线程的简单实现,即在

    s.accept()
    后,调用
    threading.Thread(target=handle_client, args=(conn, addr)).start()

  2. 多进程(Multiprocessing)

    • 原理: 类似多线程,但每个客户端连接会分配到一个独立的进程来处理。
    • 优点: 进程之间内存独立,避免了GIL的限制,可以真正实现并行计算。一个进程崩溃不会影响其他进程。
    • 缺点: 进程创建和销毁的开销比线程大得多,更消耗系统资源。进程间通信(IPC)比线程间通信复杂。
    • 适用场景: 需要利用多核CPU进行并行计算的服务器,或者对隔离性要求较高的服务。

    实现上,将

    threading.Thread
    替换为
    multiprocessing.Process
    即可,但需要注意进程间数据共享的问题。

  3. 异步I/O(Asynchronous I/O)

    • 原理: 使用单线程或少量线程,通过事件循环(event loop)来管理多个I/O操作。当一个I/O操作(如
      recv()
      )会阻塞时,它不会停下来等待,而是注册一个回调函数,然后去处理其他客户端的I/O事件。当之前的I/O操作完成后,事件循环会调用相应的回调函数。Python的
      asyncio
      模块是实现异步I/O的官方推荐方式,它基于协程(coroutine)。
    • 优点: 极高的并发性能和扩展性,资源消耗远低于多线程/多进程。特别适合I/O密集型任务。
    • 缺点: 编程范式与传统的同步编程有很大不同,需要使用
      async
      await
      关键字,学习曲线较陡峭。调试相对复杂。
    • 适用场景: 大规模高并发的网络服务,如Web服务器、API网关等。这是我个人在构建高性能网络服务时首选的方案。

    一个

    asyncio
    的Socket服务器大致结构如下:

    import asyncio
    
    async def handle_client_async(reader, writer):
        addr = writer.get_extra_info('peername')
        print(f"Connected by {addr}")
        try:
            while True:
                data = await reader.read(1024) # 异步读取
                if not data:
                    print(f"Client {addr} disconnected.")
                    break
                message = data.decode('utf-8')
                print(f"Received from {addr}: {message}")
    
                response = f"Server received: {message}"
                writer.write(response.encode('utf-8')) # 异步写入
                await writer.drain() # 确保数据发送完成
        except Exception as e:
            print(f"Error handling client {addr}: {e}")
        finally:
            writer.close()
            await writer.wait_closed() # 等待写入器关闭
    
    async def main_async():
        server = await asyncio.start_server(
            handle_client_async, '127.0.0.1', 65432
        )
        addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets)
        print(f"Serving on {addrs}")
    
        async with server:
            await server.serve_forever()
    
    # if __name__ == '__main__':
    #     asyncio.run(main_async())

选择哪种并发模型,没有绝对的答案,需要根据项目的具体需求、团队的技术栈以及预期的负载来决定。对于初学者,多线程是一个不错的起点,能够快速理解并发的机制。而对于追求极致性能和扩展性的场景,

asyncio
无疑是更现代、更强大的选择。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

492

2023.10.18

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

382

2023.10.25

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

760

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

221

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1567

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

650

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

1228

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

1204

2024.04.29

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.5万人学习

Django 教程
Django 教程

共28课时 | 5万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号