socket客户端关闭后,服务端还能收到建立连接的请求.
服务端的运行信息:
服务端代码:
#!/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)