сокет python — как завершить/закрыть соединение на стороне клиента?

#python #json #python-3.x #sockets #server

Вопрос:

server.py:

здесь используются файлы json из NVD

 import socket, json, random, threading, zipfile, requests, re, zipfile
from bs4 import BeautifulSoup
from zipfile import *
      

def listen_user(user):
    for x in range(2018,2021,1):
        filename = "nvdcve-1.1-"   str(x)   ".json"
        print(filename)
        with open(filename, 'rb') as file:
            sendfile = file.read()
        user.sendall(sendfile)
        print('file sent'   str(x))

def start_server():
    while True:
        user_socket, address = server.accept()
        print(f"User <{address[0]}> connected!")

        users.append(user_socket)
        listen_accepted_user = threading.Thread(
            target=listen_user,
            args=(user_socket,)
        )

        listen_accepted_user.start()

if __name__ == '__main__':
    users = []
    server = socket.socket(
        socket.AF_INET,
        socket.SOCK_STREAM,
    )

    server.bind(
        ("127.0.0.1", 100)
    )

    server.listen(5)
    print('waiting for connection...')
    start_server()
 

client.py

 import socket, json, random
from threading import Thread

def start_client(client):
    savefilename = str(random.randint(1,10))   'new.json'
    print(savefilename)
    with client,open(savefilename,'wb') as file:
        while True:
            recvfile = client.recv(4096)
            if not recvfile:
                print('1 client')
                break
            file.write(recvfile)
    file.close()
    print('2 client')
    client.close()


if __name__ == '__main__':
    client = socket.socket(
        socket.AF_INET,
        socket.SOCK_STREAM,
    )
    client.connect(
        ("127.0.0.1", 100)
    )
    start_client(client)
 

когда я отправляю файлы — они отправляются почти полностью, но программа не доходит до строки «печать («1 клиент») » или » печать («2 клиента»)»

и *новый файл содержит все строки, кроме нескольких десятков последних

пожалуйста, помогите — как исправить код?

Комментарии:

1. Не могли бы вы, пожалуйста, предоставить выходные pip freeze данные команды? Я не могу запустить серверный модуль из-за ошибок импорта модели.

Ответ №1:

recvfile = client.recv(4096) находится внутри цикла while и непрерывно ожидает получения следующих байтов. Клиент не знает, что файлы отправлены, поэтому он ожидает следующих 4096 байт и не выходит из цикла.

Чтобы сообщить клиенту о завершении передачи файла, вы можете отправить сообщение с server.py который вы можете проверить в клиенте и прервать цикл, как показано ниже.

server.py

 def listen_user(user):
    for x in ["f.json","g.json"]:
        filename = x
        print(filename)
        with open(filename, 'rb') as file:
            sendfile = file.read()
        user.sendall(sendfile)
        print('file sent'   str(x))
    user.send(b"Done")
 

Client.py

 def start_client(client):
    savefilename = str(random.randint(1,10))   'new.json'
    print(savefilename)
    with client,open(savefilename,'wb') as file:
        while True:
            recvfile = client.recv(4096)
            if recvfile.decode("utf-8") =="Done":
                print('1 client')
                file.close()
                break
            file.write(recvfile)
    print('2 client')
    client.close()
 

Комментарии:

1. если «Донедонедон» в recvfile. декодирование(«utf-8»): печать файла(«1 клиент»). запись(recvfile) файла разрыва. запись(recvfile)

2. спасибо за ответ, я сделал это, и программа начала работать

Ответ №2:

Вызов client.recv(4096) означает, что вы ждете получения 4096 байтов, а затем что-то делаете с этими байтами. Что, скорее всего, произойдет в этом случае, так это то, что вы записываете все байты, за вычетом тех, которые не совсем заполняют буфер в конце. Это оставляет клиента в ожидании с буфером с пространством, которое, по его мнению, еще не готово к записи.

Я предполагаю, что вы предполагаете, что client.recv() это вернет пустую строку, как только вы получите все данные; это не тот случай, основанный на вашем коде. Если вы хотите, чтобы клиент мог прервать соединение, вам нужно будет отправить какую-то управляющую последовательность или попытаться иным образом оценить байты, полученные от сервера, чтобы определить, когда пришло время закрыть соединение. Если вы сделаете это, вы, вероятно, захотите установить bufsize при вызове client.recv() значение 1 и вместо этого использовать какой-либо другой метод для буферизации перед записью в файл.

Например, поскольку вы отправляете данные JSON, вы можете объединить байты в переменную, а затем повторно попытаться проанализировать JSON. Как только вам удастся успешно проанализировать JSON, вы можете прервать соединение на стороне клиента (хотя это означало бы, что вам придется открывать новое соединение для каждого отправляемого файла).

Однако в связи с этим возникает вопрос: зачем вам нужно закрываться со стороны клиента? Обычно сервер просто закрывает соединение, как только он отправит все соответствующие данные.