服务器应答

《主机间通信》

因为项目需求,要实现一个能在程序运行过程中能与服务器做应答的功能,即传命令给服务器,并将运算结果回传。

Lib

库名:Deployment

Example

功能
  • 客户机发消息给服务器
  • 服务器回传图片给客户机
  • 客户机展示图片
客户机

import json
import socket

import numpy as np
from PIL import Image

from Deployment.clientagency import MSession,poweroff

socket.setdefaulttimeout(10)

img2list=lambda img:np.array(img).tolist()
list2img=lambda img_list:Image.fromarray(np.array(img_list,dtype=np.uint8))

if __name__ == '__main__':
    with MSession(("127.0.0.1",51888)) as conn:
        conn.Msend("give me picture.",2**2)
        jsonpacket=conn.Mrecv(2**2)
        data=json.loads(jsonpacket)
        img=list2img(data["img"])
        img.show()
服务机
import json
import time

import numpy as np
from PIL import Image

from Deployment.serveragency import Server

img2list=lambda img:np.array(img).tolist()
list2img=lambda img_list:Image.fromarray(np.array(img_list,dtype=np.uint8))

def fuc(command):
    print(command)
    img=Image.open("test.jpeg")
    data={"img":img2list(img)}
    jsonpacket=json.dumps(data)
    time.sleep(15)
    return jsonpacket

if __name__ == '__main__':
    with Server(("",51888),2**2) as worker:
        worker.loading(fuc)
        worker.run()
关闭服务器
from Deployment.clientagency import MSession,poweroff

if __name__ == '__main__':
    with MSession(("127.0.0.1",51888)) as conn:
        poweroff(conn,2**2)

Msocket

本类继承socket.socket实现了Msend&Mrecv&Maccept方法,能够在不丢包的要求下完成大文件传输。

socket.socket里的sendall&recv一旦文件长了,就会发生严重丢包。
Mscoket实现了分段发送和接受,网络不好的情况下,请刷低buffer size

#Msocket.py
import socket
import math
from socket import AddressFamily,SocketKind,getdefaulttimeout

class MMessage:
    def __init__(self,message:str,block_size=2**10):
        self.content=message.encode()
        self.len_content=len(message)
        self.block_size=block_size
    
    def __iter__(self):
        iter=0
        len_send_data=0
        len_content= self.len_content
        yield len_content.to_bytes(self.block_size,'big',signed=False)
        while len_content-len_send_data>=self.block_size:
            message_slot=self.content[iter:iter+self.block_size]
            iter+=len(message_slot)
            len_send_data+=len(message_slot)
            yield message_slot
        if len_send_data!=len_content:
            message=self.content[iter:]
            iter+=len(message)
            len_send_data+=len(message)
            assert len_send_data==len_content
            yield message


class MSocket(socket.socket):

    def __init__(self, family: AddressFamily=-1, type: SocketKind=-1, proto: int=-1, fileno: int=None) -> None:
        super().__init__(family=family, type=type, proto=proto, fileno=fileno)
    
    def Msend(self,content,block_size=2**10):
        for message_slot in MMessage(content,block_size):
            self.sendall(message_slot)
    
    def Mrecv(self,buffer_size=2**10):
        len_slot=self.recv(buffer_size)
        content_len=int.from_bytes(len_slot,byteorder='big',signed=False)
        content_recv=b''
        packet_num=math.ceil(content_len/buffer_size)
        for _ in range(packet_num):
            message_slot_recv=self.recv(buffer_size)
            content_recv+=message_slot_recv
        assert len(content_recv)==content_len
        return content_recv.decode()
    
    def Maccept(self):
        fd, addr = self._accept()
        sock = MSocket(self.family, self.type, self.proto, fileno=fd)
        if getdefaulttimeout() is None and self.gettimeout():
            sock.setblocking(True)
        return sock, addr

clientagency

供客户机部署的类

from Deployment.Msocket import MSocket
import socket

def poweroff(agency,buffer_size):
        agency.Msend('exit',buffer_size)
        feedback=agency.Mrecv(buffer_size)
        if feedback=='service stop.':
            print("the remote host is shut down.")

class MSession:

    def __init__(self,servername:tuple,selfname:tuple=None):
        assert len(servername)==2
        self.__agency=MSocket(socket.AF_INET,socket.SOCK_STREAM)
        self.__servername=servername
        if selfname is not None:
            assert len(selfname)==2
            self.__agency.bind(selfname)
    
    def __enter__(self):
        self.__agency.connect(self.__servername)
        return self.__agency
    
    def __exit__(self,*exc_info):
        self.__agency.close()
    
    @property
    def name(self):
        return self.__agency.getsockname()

serveragency

共服务器部署的类

from Deployment.Msocket import MSocket
import socket

class Server:
    def __init__(self,selfname:tuple,buffer_size):
        assert len(selfname)==2
        agency=MSocket(socket.AF_INET,socket.SOCK_STREAM)
        agency.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
        agency.setsockopt(socket.SOL_SOCKET,socket.SO_KEEPALIVE,1)
        agency.bind(selfname)
        agency.listen(5)
        self.__agency=agency
        self.service=None
        self.__buffer_size=buffer_size
    
    def loading(self,function):
        self.service=function
    
    def run(self):
        while True:
            print("providing service ...")
            client_socket,client_addr=self.agency.Maccept()
            print("From host: ",client_addr)
            command=client_socket.Mrecv(self.buffersize)
            print("runing command",command)
            if command=="exit":
                print("server stop.")
                client_socket.Msend("service stop.",self.buffersize)
                self.agency.close()
                break
            else:
                if self.service is None:
                    raise ValueError("server has no appointment yet.")
                response=self.service(command)
                client_socket.Msend(response,self.buffersize)
    
    def __enter__(self):
        return self
    
    def __exit__(self,*exc_info):
        self.agency.close()
        
    @property
    def agency(self):
        return self.__agency
    
    @property
    def buffersize(self):
        return self.__buffer_size
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值