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 网络通信中的发送端和接收端。
- NetAssist网络调试助手
- 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. 运行示例
-
启动服务器:
-
打开一个终端或命令提示符窗口,导航到包含服务器代码的文件夹,然后运行以下命令:
bashpython tcp_server.py
-
服务器将开始监听指定的端口,并等待客户端连接。
-
-
启动客户端:
-
打开另一个终端或命令提示符窗口,导航到包含客户端代码的文件夹,然后运行以下命令:
bashpython tcp_client.py
-
客户端将连接到服务器,并允许用户输入消息发送给服务器。
-
-
测试通信:
- 在客户端窗口中输入消息,按回车键发送给服务器。
- 服务器将接收消息并回显给客户端,客户端会显示服务器的响应。
- 用户可以继续发送消息,或者输入
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
库来实现异步编程。
- A: 使用多线程或多进程可以处理多个客户端的并发连接。对于更高效的方式,建议使用
-
Q: 如何确保数据传输的可靠性?
- A: TCP 协议本身就是一个面向连接的可靠协议,它会自动处理数据包的丢失、重复和乱序问题。此外,您可以在应用层添加更多的错误检测机制,如校验和或消息确认。
-
Q: 如何处理大文件传输?
- A: 对于大文件传输,建议将文件分块发送,并在每次发送后等待服务器的确认。这样可以确保每一块数据都成功传输,并且可以在出现问题时重新发送。
8. 参考资料
从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。🤣🤣🤣
- 我会持续更新对应专栏博客,非常期待你的三连!!!🎉🎉🎉
- 如果鹏鹏有哪里说的不妥,还请大佬多多评论指教!!!👍👍👍
- 下面有我的🐧🐧🐧群推广,欢迎志同道合的朋友们加入,期待与你的思维碰撞😘😘😘