我们在算法部署时,通常需要进行算法端与其他服务端的通信,要么接受指令、要么是需要上传算法结果;除了我们常用的gRPC、HTTP、MQ等方式,还可以利用TCP来实现可靠通信;本次我们利用socket来展示如何进行两端的TCP通信。
目录
[1. 服务端](#1. 服务端)
[2. 客户端](#2. 客户端)
[3. 实现效果](#3. 实现效果)
一、概念
-
TCP(传输控制协议):
- TCP是一种传输层通信协议,位于OSI模型的第四层。
- 它负责在网络中的两个主机之间提供可靠的、有序的和错误检测功能的数据传输。
- TCP确保数据包正确无误地从源传送到目的地,如果数据在传输过程中丢失或损坏,TCP会重新发送数据直到接收方正确接收到所有数据。
- TCP是面向连接的协议,这意味着在数据传输开始之前,必须在两端建立一个连接。
-
Socket(套接字):
- 套接字是网络编程中的一个端点,它提供了一种方式,允许设备上的应用程序发送和接收数据。
- 套接字是TCP/IP网络通信的一个抽象概念,它将网络协议栈封装为一个编程接口,使得开发者可以不必关心底层的网络细节。
- 在操作系统中,套接字用于实现TCP/IP模型的通信,它们可以基于不同的协议,如TCP、UDP(用户数据报协议)等。
- 套接字编程通常涉及创建套接字、绑定到一个地址和端口、监听连接(对于服务器)、接受或发起连接(对于客户端)、发送和接收数据,以及关闭连接。
二、示例代码
1. 服务端
实现思路:
-
创建Socket对象:
- 使用
socket.socket(socket.AF_INET, socket.SOCK_STREAM)
创建一个新的socket对象,用于TCP通信。
- 使用
-
绑定主机名和端口号:
host = '127.0.0.1'
表示服务器监听本地回环地址。port = 9998
指定服务器监听的端口号。server_socket.bind((host, port))
将socket与主机名和端口号绑定。
-
监听连接:
server_socket.listen(5)
开始监听连接,参数5表示允许最多5个客户端连接等待接受。
-
接受连接:
- 在
while True:
循环中,server_socket.accept()
等待并接受客户端的连接请求,返回一个新的socket对象client_socket
和客户端地址addr
。
- 在
-
接收和发送数据:
- 在另一个
while True:
循环中,client_socket.recv(1024)
接收客户端发送的数据,最大接收1024字节。 - 如果接收到的数据为空,表示客户端关闭了连接,跳出循环。
- 否则,将接收到的字符串数据尝试反序列化为字典:
json.loads(data.decode('utf-8'))
。 - 如果成功,打印接收到的字典数据,并将相同的字典数据序列化回字符串发送给客户端:
client_socket.send(json.dumps(received_dict).encode('utf-8'))
。 - 如果数据格式错误,捕获
json.JSONDecodeError
异常并打印错误信息。
- 在另一个
python
import socket
import json
def tcp_server():
# 创建socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 获取本地主机名
host = '127.0.0.1'
# 设置一个端口号
port = 9998
# 绑定端口号
server_socket.bind((host, port))
# 设置最大连接数,超过后排队
server_socket.listen(5)
# 设置超时时间
# server_socket.settimeout(10) # 10秒超时
while True:
try:
# 建立客户端连接
client_socket, addr = server_socket.accept()
print("连接地址: %s" % str(addr))
while True:
try:
# 接收小于 1024 字节的数据
data = client_socket.recv(1024)
if not data:
# 如果没有数据,跳出循环
break
else:
# 打印接收的数据
print("收到数据:", data.decode('utf-8'))
# 尝试将接收到的字符串数据反序列化为字典
try:
received_dict = json.loads(data.decode('utf-8'))
print("接收到的字典数据:", received_dict)
# 发送响应数据给客户端,这里发送相同的字典
client_socket.send(json.dumps(received_dict).encode('utf-8'))
except json.JSONDecodeError as e:
print("数据格式错误,无法解析为字典:", e)
except socket.timeout:
print("接收数据超时")
break
except ConnectionResetError:
print("连接被客户端重置")
finally:
# 关闭连接
if client_socket:
client_socket.close()
if __name__ == '__main__':
tcp_server()
2. 客户端
实现思路:
-
创建Socket对象:
- 同服务器端,使用
socket.socket(socket.AF_INET, socket.SOCK_STREAM)
创建一个新的socket对象。
- 同服务器端,使用
-
连接到服务器:
host = '127.0.0.1'
和port = 9998
指定服务器的地址和端口号。client_socket.connect((host, port))
连接到服务器。
-
发送和接收数据:
- 在
while True:
循环中,通过input("请输入数据:")
获取用户输入的数据,并发送到服务器:client_socket.send(data.encode('utf-8'))
。 - 接收服务器返回的数据:
client_socket.recv(1024)
。 - 打印来自服务器的数据:
print("来自服务器的数据:%s" % data.decode('utf-8'))
。 - 如果接收到的数据是
'exit'
,则跳出循环。
- 在
-
关闭连接:
- 在循环结束后,关闭客户端socket连接。
python
import socket
import json
import time
from tcp_messaging.api.core.tcp_messaging import TcpClient
def main():
# 获取本地主机名
host = '127.0.0.1'
# 设置服务器的端口号
port = 9998
client = TcpClient((host, port), name='client1')
client.connect()
# 创建一个字典
send_dict = {'key1': 'value1', 'key2': 'value2'}
# 将字典序列化为JSON格式的字符串
send_data = json.dumps(send_dict).encode('utf-8')
client.send(send_data)
time.sleep(1)
if client.recv(1024):
print("received success!")
client.close()
if __name__ == '__main__':
main()
3. 实现效果
客户端发送的数据及接收的返回数据:
服务端接收的数据:
参考:
https://en.wikipedia.org/wiki/Transmission_Control_Protocol