Почему поведение файлового объекта, подключенного к сокетам, отличается на стороне клиента и сервера.

Предпосылки: мы работаем над созданием графической библиотеки, в которой есть сетевой компонент, в котором сервер может выполнять абстракцию данных с интенсивными вычислениями и отправлять только соответствующие данные клиенту. Поскольку мы хотим отправлять произвольные структуры данных, мы используем pickle для преобразования экземпляров объектов Python в строки, которые отправляются через соединение с сокетом.

Код:

import socket
import threading
import SocketServer
import pickle


class Signal():

    allowed_typ = ['status','request','answer']

    def __init__(self,header,content) :
        if header in Signal.allowed_typ:
            self.header = header
        else:
            print('unknown header') 
            raise UserWarning
        self.content = content


class ThreadedTCPRequestHandler(SocketServer.StreamRequestHandler):

    def __init__(self,*args, **kwargs):
        SocketServer.StreamRequestHandler.__init__(self,*args, **kwargs)

    def handle(self):
        # self.rfile is a file-like object created by the handler;
        # we can now use e.g. readline() instead of raw recv() calls
        ## self.data = self.rfile.readline()#.strip()
        data = pickle.load(self.rfile)

        if data.header in Signal.allowed_typ:
            if data.header == 'answer':
                answer = Signal('answer',data.content + " pong ")
                pickle.dump(answer,self.wfile)
                data = pickle.load(self.rfile)
                answer = Signal('answer',data.content + " pong ")
                pickle.dump(answer,self.wfile)
        else : 
            print('server received unknown signal')
        self.rfile.close()
        self.wfile.close()

class ThreadedTCPServer(SocketServer.TCPServer):

    def __init__(self,*args,**kwargs):
        SocketServer.TCPServer.__init__(self,*args,**kwargs)
        self.status = True

if __name__ == "__main__":
    # Port 0 means to select an arbitrary unused port
    HOST, PORT = "localhost", 0

    server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
    ip, port = server.server_address
    print('server running at:',ip,':',port)

    # Start a thread with the server -- that thread will then start one
    # more thread for each request
    server_thread = threading.Thread(target=server.serve_forever)
    # Exit the server thread when the main thread terminates
    server_thread.daemon = True
    server_thread.start()
    print("Server loop running in thread:", server_thread.name)


    # sending stuff to the server
    sig = Signal('answer',' ping ')
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((ip, port))
    wf = sock.makefile(mode='wb')
    rf = sock.makefile(mode='rb')
    print('CLIENT sending \"',sig.content, '\" to server:',ip,':',port )
    pickle.dump(sig,wf)
    wf.close()    # <-----  This line
    print('CLIENT sent ',sig.content)
    try :
        response = pickle.load(rf)
        print("CLIENT Received: {} of type {} and content {}".format(response.header,type(response.content),response.content))
    except EOFError :
        print('no answer received')
    rf.close()   # <-----  This line
    sig.content = response.content + ' ping '
    wf = sock.makefile(mode='wb')
    rf = sock.makefile(mode='rb')
    print('CLIENT sending \"',sig.content, '\" to server:',ip,':',port )
    pickle.dump(sig,wf)
    wf.close()    # <-----  This line
    print('CLIENT sent ',sig.content)
    try :
        response = pickle.load(rf)
        print("CLIENT Received: {} of type {} and content {}".format(response.header,type(response.content),response.content))
    except EOFError :
        print('no answer received')
    rf.close()   # <-----  This line

    server.shutdown()
    server.server_close()

Вопрос: Почему я должен закрывать файловые объекты на стороне клиента, в то время как на стороне сервера я могу оставить их открытыми, пока не будет выполнено несколько циклов обмена данными? Соответствующие строки отмечены как "#<----- Эта строка". Если я прокомментирую одну из них, программа зависнет, потому что pickle ожидает EOF. Каков рекомендуемый вариант использования в этом сценарии? Я закрываю объект файла после каждого дампа? Почему это поведение не симметрично на стороне сервера? Как я понимаю из рассмотрения кода сокета, сокет остается открытым в любом случае, пока все объекты файла не будут закрыты.

Большое спасибо за ваше объяснение того, что происходит. С уважением. Фил

0 ответов

Другие вопросы по тегам