【TCP 网络通信(发送端 + 接收端)实例 —— Python】

TCP 网络通信(发送端 + 接收端)实例 ------ Python

  • [1. 引言](#1. 引言)
  • [2. 创建 TCP 服务器(接收端)](#2. 创建 TCP 服务器(接收端))
    • [2.1 代码示例:TCP 服务器](#2.1 代码示例:TCP 服务器)
    • [2.2 代码解释:](#2.2 代码解释:)
  • [3. 创建 TCP 客户端(发送端)](#3. 创建 TCP 客户端(发送端))
    • [3.1 代码示例:TCP 客户端](#3.1 代码示例:TCP 客户端)
    • [3.2 代码解释:](#3.2 代码解释:)
  • [4. 运行示例](#4. 运行示例)
  • [5. 异步 TCP 通信](#5. 异步 TCP 通信)
    • [5.1 异步 TCP 服务器](#5.1 异步 TCP 服务器)
    • [5.2异步 TCP 客户端](#5.2异步 TCP 客户端)
    • [5.3 代码解释:](#5.3 代码解释:)
  • [6. 总结](#6. 总结)
  • [7. 常见问题解答](#7. 常见问题解答)
  • [8. 参考资料](#8. 参考资料)

1. 引言

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。它广泛应用于互联网和局域网中,确保数据能够安全、有序地从一个设备传输到另一个设备。本文将通过具体的 Python 实例,详细介绍如何实现 TCP 网络通信中的发送端和接收端。

  1. NetAssist网络调试助手
  2. Python环境配置

准备工作

在开始编写代码之前,确保您已经安装了 Python 环境。Python 内置的 socket

模块提供了对低级网络接口的访问,因此不需要额外安装任何库。


2. 创建 TCP 服务器(接收端)

服务器端的主要任务是监听来自客户端的连接请求,并与每个连接的客户端进行双向通信。我们将使用多线程来处理多个客户端的并发连接。

2.1 代码示例:TCP 服务器

python 复制代码
import socket
import threading
import queue
import time

# 定义服务器地址和端口
HOST = '192.168.1.111'  # 本地回环地址
PORT = 8080        # 非特权端口

# 全局消息队列,用于存储服务器要发送的消息
message_queue = queue.Queue()

# 线程安全的客户端列表,存储所有已连接的客户端套接字
clients = set()

# 锁对象,确保对 clients 集合的操作是线程安全的
lock = threading.Lock()

def handle_client(client_socket, client_address):
    print(f"Connected by {client_address}")

    try:
        while True:
            # 接收来自客户端的数据
            data = client_socket.recv(1024)
            if not data:
                break  # 如果没有收到数据,退出循环
            print(f"Received from {client_address}: {data.decode()}")

            # 发送响应给客户端
            response = f"Server received: {data.decode()}"
            client_socket.sendall(response.encode())

            # 模拟服务器主动发送数据
            time.sleep(5)  # 每隔5秒检查是否有新消息
            with lock:
                if not message_queue.empty():
                    msg = message_queue.get()
                    print(f"Sending to {client_address}: {msg}")
                    client_socket.sendall(msg.encode())
    except Exception as e:
        print(f"Error handling client {client_address}: {e}")
    finally:
        # 关闭客户端连接
        with lock:
            clients.discard(client_socket)
        client_socket.close()
        print(f"Connection with {client_address} closed.")

def broadcast_message(message):
    """将消息发送给所有已连接的客户端"""
    with lock:
        for client in clients:
            try:
                client.sendall(message.encode())
            except Exception as e:
                print(f"Failed to send message to client: {e}")

def start_server():
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket:
        server_socket.bind((HOST, PORT))
        server_socket.listen()
        print(f"Server listening on {HOST}:{PORT}")

        # 启动一个后台线程,定期检查消息队列并广播消息
        threading.Thread(target=check_and_broadcast_messages, daemon=True).start()

        while True:
            client_socket, client_address = server_socket.accept()
            with lock:
                clients.add(client_socket)
            # 为每个新连接启动一个新的线程来处理
            client_thread = threading.Thread(target=handle_client, args=(client_socket, client_address))
            client_thread.start()

def check_and_broadcast_messages():
    """定期检查消息队列并广播消息"""
    while True:
        if not message_queue.empty():
            msg = message_queue.get()
            print(f"Broadcasting message: {msg}")
            broadcast_message(msg)
        time.sleep(1)  # 每隔1秒检查一次

if __name__ == "__main__":
    # 启动服务器
    threading.Thread(target=start_server, daemon=True).start()

    # 模拟服务器主动发送消息
    while True:
        msg = input("Enter message to broadcast (or type 'exit' to quit): ")
        if msg.lower() == 'exit':
            break
        message_queue.put(msg)

2.2 代码解释:

  • server_socket.bind():绑定服务器到指定的 IP 地址和端口。
  • server_socket.listen():使服务器进入监听状态,等待客户端连接。
  • server_socket.accept():接受一个客户端连接,返回一个新的套接字对象和客户端地址。
  • handle_client():处理客户端的通信,接收数据并回显给客户端。
  • threading.Thread():为每个新连接启动一个新的线程,以便服务器可以同时处理多个客户端。

运行服务端

客户端响应,发送body1,正常回传。🤞🤞🤞

3. 创建 TCP 客户端(发送端)

客户端的主要任务是连接到服务器,并与服务器进行双向通信。客户端可以发送消息给服务器,并接收服务器的响应。

3.1 代码示例:TCP 客户端

python 复制代码
import socket
import threading

# 定义服务器地址和端口
HOST = '192.168.1.101'  # 本地回环地址
PORT = 8080        # 非特权端口

client_socket = None

def receive_messages():
    global client_socket
    while True:
        try:
            # 接收服务器的响应
            response = client_socket.recv(1024).decode()
            if not response:
                break
            print(f"Received from server: {response}")
        except Exception as e:
            print(f"Error receiving message: {e}")
            break

def start_client():
    global client_socket
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_socket.connect((HOST, PORT))
    print(f"Connected to server at {HOST}:{PORT}")

    # 启动一个线程来接收消息
    receive_thread = threading.Thread(target=receive_messages)
    receive_thread.daemon = True  # 设置为守护线程,主程序退出时自动结束
    receive_thread.start()

    while True:
        # 输入要发送的消息
        message = input("Enter message to send (or type 'exit' to quit): ")
        if message.lower() == 'exit':
            break

        # 发送消息给服务器
        client_socket.sendall(message.encode())

    client_socket.close()

if __name__ == "__main__":
    start_client()

3.2 代码解释:

  • client_socket.connect():连接到指定的服务器地址和端口。
  • client_socket.sendall():发送数据到服务器。
  • client_socket.recv():接收来自服务器的数据。
  • input() :从用户输入获取要发送的消息,用户可以输入 exit 来终止程序。

4. 运行示例

  1. 启动服务器

    • 打开一个终端或命令提示符窗口,导航到包含服务器代码的文件夹,然后运行以下命令:

      bash 复制代码
      python tcp_server.py
    • 服务器将开始监听指定的端口,并等待客户端连接。

  2. 启动客户端

    • 打开另一个终端或命令提示符窗口,导航到包含客户端代码的文件夹,然后运行以下命令:

      bash 复制代码
      python tcp_client.py
    • 客户端将连接到服务器,并允许用户输入消息发送给服务器。

  3. 测试通信

    • 在客户端窗口中输入消息,按回车键发送给服务器。
    • 服务器将接收消息并回显给客户端,客户端会显示服务器的响应。
    • 用户可以继续发送消息,或者输入 exit 来终止程序。

服务端接收:

这个只能一发一收,不能连续发或连续收,接下来采用异步就可以实现这个缺陷,而且响应更好


5. 异步 TCP 通信

为了提高性能和响应速度,您可以使用 Python 的 asyncio 库来实现异步 TCP 通信。异步编程模型允许程序在等待 I/O 操作时执行其他任务,从而提高效率。

5.1 异步 TCP 服务器

我们将创建一个异步 UDP 服务器,它不仅可以接收来自客户端的数据包并回显,还可以主动向客户端发送消息。服务器将维护一个客户端列表,并定期检查是否有新消息需要发送给所有已连接的客户端。

python 复制代码
import asyncio

# 定义服务器地址和端口
HOST = '192.168.1.111'  # 本地回环地址
PORT = 8080        # 非特权端口

client_address = None

async def handle_client(reader, writer):
    global client_address
    data = await reader.read(1024)
    addr = writer.get_extra_info('peername')
    client_address = addr  # 更新全局的 client_address
    print(f"Received from {addr}: {data.decode()}")
    # 发送响应给客户端
    response = f"Server received: {data.decode()}"
    writer.write(response.encode())
    await writer.drain()
    print(f"Sent to {addr}: {response}")

async def start_server():
    server = await asyncio.start_server(handle_client, HOST, PORT)
    addr = server.sockets[0].getsockname()
    print(f"Server listening on {addr[0]}:{addr[1]}")

    async with server:
        await server.serve_forever()

async def broadcast_message():
    while True:
        msg = await asyncio.to_thread(input, "Enter message to broadcast (or type 'exit' to quit): ")
        if msg.lower() == 'exit':
            break
        if client_address is not None:  # 确保 client_address 已经被设置
            try:
                _, writer = await asyncio.open_connection(*client_address)
                writer.write(msg.encode())
                await writer.drain()
                writer.close()
                await writer.wait_closed()
            except ConnectionRefusedError:
                print("Client is not available.")
        else:
            print("No client connected yet.")

async def main():
    # 启动服务器
    server_task = asyncio.create_task(start_server())
    # 启动广播消息任务
    broadcast_task = asyncio.create_task(broadcast_message())

    await asyncio.gather(server_task, broadcast_task)

if __name__ == "__main__":
    asyncio.run(main())

5.2异步 TCP 客户端

python 复制代码
import asyncio

# 定义服务器地址和端口
HOST = '192.168.1.101'  # 本地回环地址
PORT = 8080        # 非特权端口

async def receive_messages(reader):
    while True:
        try:
            # 接收服务器的响应
            response = await reader.read(1024)
            if not response:
                break
            print(f"Received from server: {response.decode()}")
        except Exception as e:
            print(f"Error receiving message: {e}")
            break

async def send_messages(writer):
    while True:
        # 输入要发送的消息
        message = await asyncio.get_event_loop().run_in_executor(None, input, "Enter message to send (or type 'exit' to quit): ")
        if message.lower() == 'exit':
            break

        # 发送消息给服务器
        writer.write(message.encode())
        await writer.drain()

async def start_client():
    reader, writer = await asyncio.open_connection(HOST, PORT)
    print(f"Connected to server at {HOST}:{PORT}")

    # 启动两个任务:一个用于接收消息,一个用于发送消息
    receive_task = asyncio.create_task(receive_messages(reader))
    send_task = asyncio.create_task(send_messages(writer))

    # 等待任一任务完成(即用户输入 'exit' 或连接断开)
    done, pending = await asyncio.wait([receive_task, send_task], return_when=asyncio.FIRST_COMPLETED)

    # 取消所有未完成的任务
    for task in pending:
        task.cancel()
        try:
            await task
        except asyncio.CancelledError:
            pass

    writer.close()
    await writer.wait_closed()

if __name__ == "__main__":
    asyncio.run(start_client())

5.3 代码解释:

  • asyncio.Protocol:定义了一个异步协议类,用于处理客户端连接。
  • asyncio.open_connection():异步打开与服务器的连接。
  • asyncio.run():启动异步事件循环并运行主函数。
  • 只能输入英文,暂不支持中文

6. 总结

通过上述示例,我们展示了如何使用 Python 实现 TCP 网络通信中的发送端和接收端。同步版本的代码简单易懂,适合初学者;而异步版本则提供了更高的性能和更好的并发处理能力,适用于更复杂的应用场景。🛹🛹🛹


7. 常见问题解答

  • Q: 如何处理多个客户端的并发连接?

    • A: 使用多线程或多进程可以处理多个客户端的并发连接。对于更高效的方式,建议使用 asyncio 库来实现异步编程。
  • Q: 如何确保数据传输的可靠性?

    • A: TCP 协议本身就是一个面向连接的可靠协议,它会自动处理数据包的丢失、重复和乱序问题。此外,您可以在应用层添加更多的错误检测机制,如校验和或消息确认。
  • Q: 如何处理大文件传输?

    • A: 对于大文件传输,建议将文件分块发送,并在每次发送后等待服务器的确认。这样可以确保每一块数据都成功传输,并且可以在出现问题时重新发送。

8. 参考资料


从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。🤣🤣🤣

  1. 我会持续更新对应专栏博客,非常期待你的三连!!!🎉🎉🎉
  2. 如果鹏鹏有哪里说的不妥,还请大佬多多评论指教!!!👍👍👍
  3. 下面有我的🐧🐧🐧群推广,欢迎志同道合的朋友们加入,期待与你的思维碰撞😘😘😘
相关推荐
老大白菜18 分钟前
正则表达式完全指南
python
西猫雷婶35 分钟前
python学opencv|读取图像(三十一)缩放图像的三种方法
开发语言·python·opencv
处女座_三月36 分钟前
多并发发短信处理(头条项目-07)
java·前端·数据库·python
&白帝&41 分钟前
Java 方法
java·开发语言·python
zhangfeng11331 小时前
Selenium python爬虫 是否需要设置浏览器窗口大小 ,有些按钮显示 不全会导致无法正常与这些元素进行交互
爬虫·python·selenium
王子良.1 小时前
使用 Python 实现自动化办公(邮件、Excel)
python·自动化·excel
郁大锤1 小时前
Windows 下安装 PyTorch 的常见问题及解决方法
人工智能·python
胡子哥5021 小时前
Windows自动化Python pyautogui RPA操作
windows·python·自动化·pyautogui·rpa
weixin_307779131 小时前
Python的Langchain库的功能及实现代码
人工智能·python·langchain
处女座_三月1 小时前
用户注册模块用户校验(头条项目-05)
前端·javascript·python·django