socket客户端关闭后,为什么服务端还能收到建立连接的请求?

新手上路,请多包涵

socket客户端关闭后,服务端还能收到建立连接的请求.

服务端的运行信息:
image.png

服务端代码:

#!/usr/bin/env python
# -*- coding=utf-8 -*-
"""
file: socket_server.py
"""

import socket
import threading
import sys
import os
import struct
import json
import subprocess
from tqdm import tqdm

server_port = 11000


def send_text(conn, obj):
    if isinstance(obj, dict):
        info = json.dumps(obj)
    else:
        info = obj
    info_bytes = info.encode('utf-8')
    bytes_length = struct.pack('i', len(info_bytes))
    conn.send(bytes_length)
    conn.send(info_bytes)


def recv_text(conn):
    length_struct = conn.recv(4)

    print("recv_text:type=".format(type(length_struct)))
    print("recv_text:length_struct=".format(length_struct))
    info_length = struct.unpack('i', length_struct)[0]
    print("recv_text:info_length=".format(info_length))
    bytes_info = conn.recv(info_length)
    print("recv_text:bytes_info {}".format(bytes_info))
    info = bytes_info.decode('utf-8')
    return info


def execute(cmd):
    try:
        status, output = subprocess.getstatusoutput(cmd)
        return output
    except subprocess.CalledProcessError as e:
        out_bytes = e.output  # Output generated before error
        code = e.returncode  # Return code


def get_header(conn):
    header = recv_text(conn)
    json_header = json.loads(header)
    print("json_header {}".format(json_header))
    return json_header


def start_server():
    try:
        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server.bind(('', server_port))
        server.listen(10)
    except socket.error as msg:
        print(msg)
        sys.exit(1)
    print('Waiting connection...')

    while True:
        conn, addr = server.accept()
        # t = threading.Thread(target=deal_data, args=(conn, addr))
        # t.start()
        deal_data(conn,addr)


def build_filename(target_dir, filename):
    new_filename = target_dir
    if target_dir.endswith("/"):
        if not os.path.exists(target_dir):
            os.makedirs(target_dir)
        new_filename = os.path.join(target_dir, filename)
    return new_filename


def store(conn, filename, filesize):
    recvd_size = 0  # 定义已接收文件的大小
    fp = open(filename, 'wb')
    print('start receiving...')

    while not recvd_size >= filesize:
        if filesize - recvd_size > 10240:
            data = conn.recv(10240)
            recvd_size += len(data)
        else:
            data = conn.recv(filesize - recvd_size)
            recvd_size += len(data)
        fp.write(data)
    print("will close file")
    fp.close()
    print('end receive...')


def give(conn, path):
    if os.path.isfile(path):
        file_size = os.stat(path).st_size
        bytes_length = struct.pack('i', file_size)
        conn.send(bytes_length)
        with tqdm(total=file_size, desc='文件下载', ncols=100, leave=True, unit='B', unit_scale=True) as pbar:
            fp = open(path, 'rb')
            while True:
                data = fp.read(1024)
                if not data:
                    print('{0} file send over...'.format(path))
                    break
                conn.send(data)
                pbar.update(len(data))


def deal_data(conn, addr):
    print('{}. Accept new connection from {}'.format(threading.currentThread().getName(), addr))

    while True:
        header = get_header(conn)
        action = header.get('action')
        print("deal_data:action is {}".format(action))

        if action is None:
            print("ERROR: The 'action' argument should be one of put/get/del/look")
        elif action == "put":
            filename = header['name']
            target_dir = header['dir']
            file_size = header['length']
            print("target dir {}".format(target_dir))
            print("filename {}".format(filename))
            new_filename = build_filename(target_dir, filename)
            print('file new name is {0}, file size is {1} , dir is  {2}'.format(new_filename, file_size, target_dir))
            store(conn, new_filename, file_size)
        elif action == "get":
            path = header.get("path")
            give(conn, path)
        elif action == "cmd":
            cmd = header.get("cmd")
            result = execute(cmd)
            if len(result) == 0:
                result = "命令{}执行完了!".format(cmd)
            send_text(conn, result)
            print("命令 {} 已经执行了!".format(cmd))

        conn.close()
        break


if __name__ == '__main__':
    if len(sys.argv) > 1:
        server_port = int(sys.argv[1])
    print("server port is {}".format(server_port))
    start_server()

客户端代码:

#!/Users/wangjunbo/opt/anaconda3/bin/python3
# -*- coding=utf-8 -*-
"""
file: socket_client.py
socket client
"""

import socket
import os
import re
import sys
import struct
import json
from tqdm import tqdm

server_host = "49.234.136.178"
server_port = 11000

# source_path = None
source_children = []
target_dir = None
target_path = None  # get/del/ls等命令用到
target_cmd = None


def send_text(conn, obj):
    if isinstance(obj, dict):
        info = json.dumps(obj)
    else:
        info = obj
    info_bytes = info.encode('utf-8')
    bytes_length = struct.pack('i', len(info_bytes))
    conn.send(bytes_length)
    conn.send(info_bytes)


def recv_text(conn):
    length_struct = conn.recv(4)
    info_length = struct.unpack('i', length_struct)[0]
    bytes_info = conn.recv(info_length)
    info = bytes_info.decode('utf-8')
    return info


def build_header(action):
    global target_path
    file_info = {'action': action}
    if action == "put":
        file_info['dir'] = target_dir
    elif action == "cmd":
        file_info['cmd'] = target_cmd
    else:
        file_info['path'] = target_path

    return json.dumps(file_info)


def parse_target_args(action, args):
    global server_host
    global server_port
    global target_dir
    global target_path
    global target_cmd
    global source_children

    arg_line = " ".join(args)
    print(arg_line)

    result = re.findall(r"[^\d.]*([\d.]+):(\d{3,5})[/ ].*", arg_line)
    if result:
        result = result[0]
        if len(result) == 2:
            print(result)
            server_host, server_port = result
            server_port = int(server_port)

    print("server_host={}".format(server_host))
    print("server_port={}".format(server_port))
    if action == 'put':
        target_dir = re.findall(r".*?(/[/\w.]+)(\s.*|$)", args[1])
        target_dir = target_dir[0][0]
        print("target_dir={}".format(target_dir))
        source_path = args[0]
        if not os.path.exists(source_path):
            print("ERROR, 这个路径不存在{}".format(source_path))
            sys.exit(1)
        if os.path.isdir(source_path):
            children = os.listdir(source_path)
            source_children = list(
                filter(lambda f: not f.startswith(".") and os.path.isfile(os.path.join(source_path, f)), children))
            source_children = list(map(lambda f: os.path.join(source_path, f), children))
        else:
            source_children.append(args[0])
        print("source_children={}".format(source_children))

    if action in ['put', 'get', 'del', 'der', 'look']:
        if len(re.findall(r":(\d{3,5})", arg_line)) > 0:
            target_path = re.findall(r".*:\d+(/[/\w.]+)(\s.*|$)", arg_line)
            target_path = target_path[0][0]
        else:
            target_path = args[1]
        print("target_path={}".format(target_path))
    elif action == 'cmd':
        if len(args) == 2:
            target_cmd = args[1]
        elif len(args) == 1:
            target_cmd = args[0]
        print("target_cmd={}".format(target_cmd))


def upload(client, filepath, target_dir):
    file_info = {'action':'put' , 'name': os.path.basename(filepath), "length": os.stat(filepath).st_size, "dir": target_dir}
    send_text(client, file_info)
    file_size = os.stat(filepath).st_size
    # with tqdm(total=file_size, desc='文件上传', ncols=100, leave=True, unit='B', unit_scale=True) as pbar:
    fp = open(filepath, 'rb')
    while True:
        data = fp.read(10240)
        if not data:
            print('{0} file send over...'.format(filepath))
            break
        client.send(data)
            # pbar.update(len(data))


def store(conn, filename, filesize):
    recvd_size = 0  # 定义已接收文件的大小
    fp = open(filename, 'wb')
    print('start receiving...')

    while not recvd_size >= filesize:
        if filesize - recvd_size > 10240:
            data = conn.recv(10240)
            recvd_size += len(data)
        else:
            data = conn.recv(filesize - recvd_size)
            recvd_size += len(data)
        fp.write(data)
    fp.close()
    print('end receive...')


def build_client(action):
    global target_dir
    global target_path
    global source_children
    try:
        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        client.connect((server_host, server_port))
        print("和服务器{}:{}建立连接!\n".format(server_host, server_port))
    except socket.error as msg:
        print(msg)
        sys.exit(1)

    while True:

        if action in ['get', 'der', 'look', 'cmd']:
            fileinfo = build_header(action)
            send_text(client, fileinfo)

        if action == "put":
            if source_children:
                for fp in source_children:
                    print("will upload {}".format(fp))
                    upload(client, fp, target_dir)
        elif action == "get":
            filename = os.path.basename(target_path)
            b_info_length = client.recv(4)
            file_size = struct.unpack('i', b_info_length)[0]
            print("filename={} and filesize={}".format(filename, file_size))
            store(client, filename, file_size)
        elif action in ["look", "cmd"]:
            info = recv_text(client)
            print(info)

        print("client 关闭".format(client.family))
        client.close()
        break


if __name__ == '__main__':
    action = sys.argv[1]
    parse_target_args(action, sys.argv[2:])
    build_client(action)
阅读 1.3k
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进