基于socket实现客户端与服务器之间TCP通信

我们在算法部署时,通常需要进行算法端与其他服务端的通信,要么接受指令、要么是需要上传算法结果;除了我们常用的gRPC、HTTP、MQ等方式,还可以利用TCP来实现可靠通信;本次我们利用socket来展示如何进行两端的TCP通信。

目录

一、概念

二、示例代码

[1. 服务端](#1. 服务端)

[2. 客户端](#2. 客户端)

[3. 实现效果](#3. 实现效果)

参考:


一、概念

  1. TCP(传输控制协议):

    • TCP是一种传输层通信协议,位于OSI模型的第四层。
    • 它负责在网络中的两个主机之间提供可靠的、有序的和错误检测功能的数据传输。
    • TCP确保数据包正确无误地从源传送到目的地,如果数据在传输过程中丢失或损坏,TCP会重新发送数据直到接收方正确接收到所有数据。
    • TCP是面向连接的协议,这意味着在数据传输开始之前,必须在两端建立一个连接。
  2. 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

https://en.wikipedia.org/wiki/Network_socket

TCP(传输控制协议)_百度百科

套接字_百度百科

相关推荐
发光小北2 小时前
EtherNet/IP 转 ModbusTCP 网关现场应用中会遇到什么问题?
服务器·网络·tcp/ip
开源必胜4 小时前
Socket、异步非阻塞 I/O 与 NGINX、Netty 模型
网络·tcp/ip·nginx
沫璃染墨4 小时前
从零入门计算机网络系列(十一):HTTP协议进阶——从重定向原理到GET/POST与Fiddler抓包
linux·服务器·开发语言·网络·c++·tcp/ip·html
箓维5 小时前
TCP Socket的进阶实现
网络·笔记·tcp/ip
星恒随风6 小时前
Linux网络编程:应用层协议究竟是什么?从网络计算器到TCP Socket抽象基类完整实现
linux·网络·笔记·tcp/ip
万联WANFLOW6 小时前
异地组网速度忽快忽慢到底怎么回事?直连与中继的判断方法和处理步骤
运维·网络·网络协议·p2p
步行cgn9 小时前
HTTP 请求报文结构详解:请求行、请求头、请求体各自的作用
网络·网络协议·http
Escalating_xu10 小时前
【Linux 网络编程】ARP 的具体过程与 ARP 欺骗:一条 IP → MAC 映射,怎样改变数据的去向?
linux·网络·tcp/ip
搞科研的小刘选手10 小时前
【广州大学主办 | IEEE出版 | 落地广州】第八届国际科技创新学术交流大会暨通信、信息系统和软件工程学术会议(CISSE 2026)
软件工程·通信·信息系统·学术会议·广州大学·科技创新·会议推荐
Escalating_xu11 小时前
【Linux 网络编程】IP 分片与重组:3000 字节的数据报,怎样拆开又拼回来?
linux·网络·tcp/ip