python socket - 如何complete/close 客户端连接?

python socket - how to complete/close the connection on the client side?

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)

当我发送文件时 - 它们几乎全部发送,但程序没有到达“print ('1 client')”或“print ('2 client')”行

*新文件包含除最后几行之外的所有行

请帮忙 - 如何修复代码?

调用 client.recv(4096) 意味着您正在等待接收 4096 个字节,然后对这些字节进行处理。在这种情况下可能发生的情况是,您正在写出所有字节,减去那些最后没有完全填满缓冲区的字节。这让客户端等待 space 的缓冲区认为它还没有准备好写出。

我猜你是在假设 client.recv() 将在你获得所有数据后 return 一个空字符串;根据您的代码,情况并非如此。如果您希望客户端能够终止连接,您将需要发送某种控制序列或尝试以其他方式评估从服务器接收到的字节以确定何时关闭连接。如果这样做,您可能希望在调用 client.recv() 时将 bufsize 设置为 1,而不是在写入文件之前使用其他方法进行缓冲。

例如,由于您正在发送 JSON 数据,您可以将字节连接到一个变量,然后重复尝试解析 JSON。成功解析 JSON 后,您可以在客户端终止连接(尽管这意味着您必须为每个要发送的文件打开一个新连接)。

但是,这就提出了一个问题:为什么需要从客户端关闭?通常服务器会在发送完所有相关数据后关闭连接。

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()