Python中socket通信

main函数自定义,针对个人需求处理发送的消息和接收的数据,以下是Server,为了保证传输的数据完整性,增加简单的数据校验,在发送的数据前加标志位,如:#234,代表以#开始,#后一位数代表后面34的长度为2,34则代表发送的数据的长度。

import json
import socket
import threading
import time
from socket import AF_INET, SOCK_STREAM
from typing import Union


class SocketServer:
    def __init__(self, ip: str, port: int):
        # 一般大写字母用来表示配置信息
        self.server = None
        self.client_address = None
        self.client_socket = None
        self.SERVER_IP = ip
        print(self.SERVER_IP)
        self.SERVER_PORT = port
        self.BUF_LEN = 1024  # 一次性接受的最大字节数
        self.__start_server()

        self.__keep_runing = True
        threading.Thread(target=self.__ping_clients).start()

    def __start_server(self):
        self.server = socket.socket(AF_INET, SOCK_STREAM)  # 监听端口,使用INET即为网络层使用IP协议,STREAM表示传输层使用TCP协议
        self.server.bind((self.SERVER_IP, self.SERVER_PORT))  # 监听端口需要绑定ip地址和端口号,bind中只能是一个参数,因此使用元组传参
        self.server.listen(5)  # 最多接受五个等待连接的客户端

    def __wait_client(self):
        client_socket, client_address = self.server.accept()  # 等待新客户端连接
        print("连接已建立:", client_address)
        self.client_socket = client_socket
        self.client_address = client_address

    def send(self, data):
        """
        仅仅发送消息,无需等待返回值
        :param data:
        :return:
        """
        msg_length = str(len(data))
        command = f"#{len(msg_length)}{msg_length}{data}"
        self.client_socket.sendall(command.encode("utf-8"))

    def recvive(self):
        # 接收客户端的消息
        data = self.client_socket.recv(self.BUF_LEN)
        if not data:  # 连接已关闭
            return None
        else:
            message = data.decode("utf-8")
            print("收到客户端消息:", message)
            return message

    def __ping_clients(self):
        """
        判断连接是否存活
        """
        while self.__keep_runing:
            if self.client_socket:
                try:
                    self.send("ping")
                except socket.error:
                    # Client is most likely disconnected
                    print("连接已关闭:", self.client_address)
                    self.client_socket = None
                    self.client_address = None
            else:
                ...
            time.sleep(5)
        else:
            print(f"线程停止!")

    def send_msg(self, command: Union[dict, str]):
        """
        发送消息并等待返回
        :param command:
        :return:
        """
        if isinstance(command, dict):
            command = json.dumps(command)
        else:
            ...

        while True:
            if self.client_socket:
                self.send(command)
                # 接收客户端的消息
                message = self.recvive()
                if message == 'ok':
                    # 回复客户端
                    response = f"已收到消息:{message}"
                    self.send(response)
                    break
                elif message == 'no':
                    print(f"Send again")
                    time.sleep(3)
                    continue
                else:
                    break
            else:
                self.__wait_client()
                continue

    def close(self):
        self.__keep_runing = False
        self.client_socket.close()
        self.server.close()


def main():
    server = SocketServer('127.0.0.1', 8888)
    cmd = {'start_test': ''}
    server.send_msg(cmd)
    time.sleep(10)
    server.send_msg('close')
    server.close()


if __name__ == '__main__':
    main()

Client客户端,将接收到的字典保存到txt中

import threading
import time
from pathlib import Path
from socket import socket



TXT_PATH = Path.cwd() / 'data.txt'


class SocketClient:
    def __init__(self, server_ip: str, server_port: int):
        self.command = None
        self.BUF_LEN = 1024
        self.server_socket = socket()
        server_address = (server_ip, server_port)
        self.server_socket.connect(server_address)
        self.keep_running = True

    def start_receive(self):
        threading.Thread(target=self.__receive_ping).start()

    def send(self, msg):
        self.server_socket.send(msg.encode())

    @staticmethod
    def __check_data(data: str):
        """
        检查收到的信息是否完整
        :param data:
        :return:
        """
        idx = data.find('#')
        length_of_data_len = int(data[idx + 1])
        data_length = int(data[idx + 2: idx + 2 + length_of_data_len])
        msg = data[idx + 2 + length_of_data_len:]
        if len(msg) == data_length:
            return msg
        else:
            return False

    def __receive_ping(self):
        """
        接收心跳信息
        """
        while self.keep_running:
            recv_data = self.server_socket.recv(self.BUF_LEN).decode()  # 发送完数据,等待接受不超过1024字节的回应数据
            msg = self.__check_data(recv_data)
            if msg is False:
                self.send('no')
                continue
            elif msg == 'ping' or not recv_data:
                ...
            elif msg == '已收到消息:ok':
                pass
            elif msg == 'close':
                self.command = msg
                self.close()
                break
            else:
                self.command = msg
                print(msg)
                self.__save_task_to_txt(msg)
                self.send('ok')
        else:
            print(f'线程停止!')

    @staticmethod
    def __save_task_to_txt(msg: str):
        data = eval(msg)
        if type(data) != dict:
            return
        with open(TXT_PATH, 'w') as f:
            for func in data:
                f.write('{'+f"'{func}': '{data[func]}'"+'}\n')

    def close(self):
        self.keep_running = False
        self.server_socket.close()

def main():
    ip = '127.0.0.1'
    client = SocketClient(ip, 8888)
    client.start_receive()  # 开启线程接收消息

你可能感兴趣的:(python,网络,开发语言,websocket)