python实现同一个服务器对应多个客户端进行通信

本代码实现的功能为:服务器将客户端A发送的信息(json串)进行处理,并转发给客户端B。
客户端A的请求端口为19005,客户端B的请求端口为19004
具体实现功能代码如下:

1.客户端A向服务端发送信息(以json为例):
from socket import *

def client():
    # 创建socket
    tcp_client_socket = socket(AF_INET, SOCK_STREAM)

    # 目的信息
    server_ip = "127.0.0.1"   #服务端ip
    server_port = 19005     #端口

    # 链接服务器
    tcp_client_socket.connect((server_ip, server_port))
    
    #客户端向服务端发送json串
    data = 'S010712320039{"datas":[{"PN":"P1","PathID":"","StopID":"3","Type":2,"PositionX":1.000,"PositionY":0.000,"Speed":0.255,"CornerAngle":0}]}E'
    tcp_client_socket.send(data.encode('utf-8'))

    # 接收服务端返回数据,最大接收1024个字节
    recvData = tcp_client_socket.recv(1024)
    print('接收到的数据为:', recvData.decode('gbk'))

    # 关闭套接字
    tcp_client_socket.close()

if __name__ == "__main__":
    client()
2.服务端接收json串之后进行处理,转发给客户端B,代码如下:
#! /usr/bin/env python3
import json
from math import *
from socket import *

1)###欧拉角转四元素

def QuaterniondtoQuaternion(yaw, pitch, roll):   # yaw (Z), pitch (Y), roll (X)

    # // Abbreviations for the various angular functions
    cy = cos(yaw * 0.5)
    sy = sin(yaw * 0.5)
    cp = cos(pitch * 0.5)
    sp = sin(pitch * 0.5)
    cr = cos(roll * 0.5)
    sr = sin(roll * 0.5)

    q0 = cy * cp * cr + sy * sp * sr  
    q1 = cy * cp * sr - sy * sp * cr
    q2 = sy * cp * sr + cy * sp * cr
    q3 = sy * cp * cr - cy * sp * sr
    
    q0 = round(q0, 3)
    q1 = round(q1, 3)
    q2 = round(q2, 3)
    q3 = round(q3, 3)
    
    #注意返回值的顺序
    return q1,q2,q3,q0    #qx, qy, qz, qw
    

2)###接收客户端A的信息,进行数据处理,并返回校验数据

def server1(ip,port):

    # 创建socket
    tcp_server_socket = socket(AF_INET, SOCK_STREAM)
    #服务器ip与端口
    address = (ip, port)
    # 绑定
    tcp_server_socket.bind(address)
    #设置监听数.
    tcp_server_socket.listen(5)
    client_socket, clientAddr = tcp_server_socket.accept()
    # 接收对方发送过来的数据,和udp不同返回的只有数据
    recv_data = client_socket.recv(1024).decode('utf-8')  # 接收1024个字节,
  
    #处理接收的信息,截取{}中的信息,进行数据处理
    data = recv_data[13:-1]
    # print(data)  
    #json解析 str--->dict 先把字符串转换为字典
    data_dict = json.loads(data)
    # 只取字典data_dict['datas']的值
    dict_value = data_dict['datas'][0]
    # print(dict_value)
    global tup
    #需要转发的信息数据进行处理(符合目标格式)
    tup = (dict_value['PositionX'],dict_value['PositionY'],QuaterniondtoQuaternion(dict_value['CornerAngle'], 0, 0))
    print('接收的导航点为',tup)

    # 接收到数据,返回信息校验(向客户端A返回信息)
    data2 = 'T'+ recv_data[1:13].ljust(36,'0') + 'E'
    # print(data2)
    client_socket.send(data2.encode())
    
    #关闭连接
    client_socket.close()


3)#将处理之后的数据转发给客户端B

def server2(ip,port):

    tcp_server_socket = socket(AF_INET, SOCK_STREAM)
    address = (ip, port)
    tcp_server_socket.bind(address)
    tcp_server_socket.listen(2)
    client_socket, clientAddr = tcp_server_socket.accept()
    
    #调用server1, 客户端A连接的端口为19005
    server1('127.0.0.1',19005)  
    #判断是否接收到信息,如果不是空,则转发到客户端B
    if tup:
        client_socket.send(str(tup).encode())

    # 接收客户端B的返回信息
    # recv_data = client_socket.recv(1024).decode('utf-8')  # 接收1024个字节,
    # print('接收到的数据为:', recv_data.decode('utf-8'))

    # 关闭为这个客户端服务的套接字,只要关闭了,就意味着为不能再为这个客户端服务了,如果还需要服务,只能再次重新连接
    client_socket.close()
    

4)主函数运行

if __name__ == "__main__":

    while(1):  #服务端始终运行
        server2('127.0.0.1', 19004)  #客户端B请求端口为19004
        # time.sleep(20)   

在Ubuntu中运行可能存在问题:
在这里插入图片描述

  1. 主要是因为防止服务端紧接着进行下一次链接,出现 OSError : [Errno 98] Address already in use. 出现这个错误的原因:在TCP/IP终止连接的第四次握手中,当最后的ACK回复发出后,有个2MSL的时间等待,MSL指一个片段在网络中最大的存活时间,这个时间一般是30秒,所以基本上过60秒后就可以重新连接!
    为什么要等待2MSL?是因为在最后发出ACK回复后,发送方不能确认ACK是否被另一端正常收到,如果另一端没有收到ACK回复的话,将会在1MSL后再次发送FIN片段。所以说发送方等待2MSL时间,也就是刚好它发ACK回复和对方发送FIN片段的时间,如果此时间内都没有再次收到FIN片段的话,发送方就假设对方已经正常接收到了ACK回复,此时它就会正常关闭连接!
  2. 解决:
    修改代码,tcp_server_socket2.bind(address2)等代码不要放在循环中,避免短时间内不断重复申请连接。
3.客户端B接收服务端信息,和客户端A的实现是一样的
from socket import *

def client():
    # 创建socket
    tcp_client_socket = socket(AF_INET, SOCK_STREAM)
    
    # 目的信息
    server_ip = "127.0.0.1"
    server_port = 19004
    
    # 链接服务器
    tcp_client_socket.connect((server_ip, server_port))

    while(1):
        ## 接收对方发送过来的数据,最大接收1024个字节
        recvData = tcp_client_socket.recv(1024)
        print('接收到的数据为:', recvData.decode('gbk'))
        if recvData:   #如果接收到数据不为空
            tcp_client_socket.send('1111'.encode('utf-8'))
            time.sleep(5)
        else:
            break

    # 关闭套接字
    tcp_client_socket.close()

if __name__ == "__main__":
    client()
4.运行结果展示

先运行服务端,再运行客户端B,最后运行客户端A
在这里插入图片描述
如果发现任何疑问,欢迎留言指教。三克油~~

python实现TCP通信,参考链接:
Python实现TCP程序
Python实现TCP程序

  • 6
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,我可以给您提供一个简单的 Python 程序示例,实现客户端启动多个线程向服务器端连续请求数据服务,服务器可提供分类的数据服务等。以下是代码示例: 服务器端代码: ```python import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): def handle(self): while True: data = self.request.recv(1024) if not data: break # 根据客户端请求的服务类型,返回对应的数据 if data == b'type1': self.request.sendall(b'service1 data') elif data == b'type2': self.request.sendall(b'service2 data') else: self.request.sendall(b'unknown service') if __name__ == "__main__": HOST, PORT = "localhost", 9999 server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) server.serve_forever() ``` 客户端代码: ```python import threading import socket class ClientThread(threading.Thread): def __init__(self, threadID, name, server_address, service_type): threading.Thread.__init__(self) self.threadID = threadID self.name = name self.server_address = server_address self.service_type = service_type def run(self): print("Starting " + self.name) # 创建一个 TCP/IP 套接字 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 连接服务器端 sock.connect(self.server_address) try: # 发送服务类型请求 sock.sendall(self.service_type.encode()) # 接收数据 data = sock.recv(1024) print("{}: {}".format(self.name, data)) finally: # 关闭套接字 sock.close() if __name__ == "__main__": # 服务器端地址 server_address = ("localhost", 9999) # 创建多个客户端线程 threads = [] for i in range(5): thread = ClientThread(i, "Thread-{}".format(i), server_address, "type1") threads.append(thread) for i in range(5, 10): thread = ClientThread(i, "Thread-{}".format(i), server_address, "type2") threads.append(thread) # 启动所有线程 for thread in threads: thread.start() # 等待所有线程完成 for thread in threads: thread.join() ``` 以上代码示例中,服务器端使用 socketserver 库创建 TCP 服务器客户端使用 socket 库创建 TCP 客户端,每个客户端一个独立的线程中运行。客户端线程向服务器发送服务类型请求,服务器根据请求类型返回对应的数据。如果请求类型未知,则返回“unknown service”提示信息。客户端接收到数据后打印输出,然后关闭套接字。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值