239 lines
7.7 KiB
Python
239 lines
7.7 KiB
Python
import socket
|
||
import json
|
||
import time
|
||
import sys
|
||
from datetime import datetime
|
||
|
||
# 设置标准输出编码为 UTF-8(解决 Windows 控制台编码问题)
|
||
if sys.platform.startswith('win'):
|
||
import codecs
|
||
sys.stdout = codecs.getwriter('utf-8')(sys.stdout.detach())
|
||
sys.stderr = codecs.getwriter('utf-8')(sys.stderr.detach())
|
||
# 设置标准输入编码
|
||
sys.stdin = codecs.getreader('utf-8')(sys.stdin.detach())
|
||
|
||
class JSONSocketClient:
|
||
def __init__(self, host='localhost', port=8888):
|
||
self.host = host
|
||
self.port = port
|
||
self.socket = None
|
||
self.connected = False
|
||
|
||
def connect(self):
|
||
"""连接到服务器"""
|
||
try:
|
||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||
self.socket.connect((self.host, self.port))
|
||
self.connected = True
|
||
print(f"✅ 已连接到服务器 {self.host}:{self.port}")
|
||
return True
|
||
except Exception as e:
|
||
print(f"❌ 连接失败: {e}")
|
||
return False
|
||
|
||
def disconnect(self):
|
||
"""断开连接"""
|
||
if self.socket:
|
||
self.socket.close()
|
||
self.connected = False
|
||
print("🔌 已断开连接")
|
||
|
||
def send_request(self, request):
|
||
"""发送请求并接收响应"""
|
||
if not self.connected:
|
||
print("❌ 未连接到服务器")
|
||
return None
|
||
|
||
try:
|
||
# 发送请求
|
||
request_json = json.dumps(request, ensure_ascii=False)
|
||
self.socket.send(request_json.encode('utf-8'))
|
||
print(f"📤 发送请求: {request_json}")
|
||
|
||
# 接收响应
|
||
response_data = self.socket.recv(4096).decode('utf-8')
|
||
response = json.loads(response_data)
|
||
print(f"📥 收到响应: {json.dumps(response, ensure_ascii=False, indent=2)}")
|
||
|
||
return response
|
||
|
||
except Exception as e:
|
||
print(f"❌ 请求失败: {e}")
|
||
return None
|
||
|
||
def send_message(self, message):
|
||
"""发送普通消息(非 JSON 格式)"""
|
||
if not self.connected:
|
||
print("❌ 未连接到服务器")
|
||
return None
|
||
|
||
try:
|
||
self.socket.send(message.encode('utf-8'))
|
||
print(f"📤 发送消息: {message}")
|
||
|
||
response_data = self.socket.recv(4096).decode('utf-8')
|
||
response = json.loads(response_data)
|
||
print(f"📥 收到响应: {json.dumps(response, ensure_ascii=False, indent=2)}")
|
||
|
||
return response
|
||
|
||
except Exception as e:
|
||
print(f"❌ 发送消息失败: {e}")
|
||
return None
|
||
|
||
def get_file(self, filename='test_data.json'):
|
||
"""从服务器获取文件"""
|
||
request = {
|
||
"command": "get_file",
|
||
"filename": filename,
|
||
"timestamp": datetime.now().isoformat()
|
||
}
|
||
return self.send_request(request)
|
||
|
||
def save_file(self, filename, content):
|
||
"""保存文件到服务器"""
|
||
request = {
|
||
"command": "save_file",
|
||
"filename": filename,
|
||
"content": content,
|
||
"timestamp": datetime.now().isoformat()
|
||
}
|
||
return self.send_request(request)
|
||
|
||
def list_files(self):
|
||
"""列出服务器上的 JSON 文件"""
|
||
request = {
|
||
"command": "list_files",
|
||
"timestamp": datetime.now().isoformat()
|
||
}
|
||
return self.send_request(request)
|
||
|
||
def ping(self):
|
||
"""测试服务器连接"""
|
||
request = {
|
||
"command": "ping",
|
||
"timestamp": datetime.now().isoformat()
|
||
}
|
||
return self.send_request(request)
|
||
|
||
def interactive_mode(self):
|
||
"""交互模式"""
|
||
print("\n🎮 进入交互模式")
|
||
print("可用命令:")
|
||
print(" 1. get <filename> - 获取文件")
|
||
print(" 2. save <filename> - 保存文件(会提示输入内容)")
|
||
print(" 3. list - 列出文件")
|
||
print(" 4. ping - 测试连接")
|
||
print(" 5. msg <message> - 发送普通消息")
|
||
print(" 6. quit - 退出")
|
||
print()
|
||
|
||
while self.connected:
|
||
try:
|
||
command = input("👉 请输入命令: ").strip()
|
||
|
||
if not command:
|
||
continue
|
||
|
||
parts = command.split(' ', 1)
|
||
cmd = parts[0].lower()
|
||
|
||
if cmd == 'quit':
|
||
break
|
||
elif cmd == 'get':
|
||
filename = parts[1] if len(parts) > 1 else 'test_data.json'
|
||
self.get_file(filename)
|
||
elif cmd == 'save':
|
||
filename = parts[1] if len(parts) > 1 else 'new_data.json'
|
||
print("请输入要保存的 JSON 内容(输入空行结束):")
|
||
lines = []
|
||
while True:
|
||
line = input()
|
||
if not line:
|
||
break
|
||
lines.append(line)
|
||
|
||
if lines:
|
||
try:
|
||
content = json.loads('\n'.join(lines))
|
||
self.save_file(filename, content)
|
||
except json.JSONDecodeError as e:
|
||
print(f"❌ JSON 格式错误: {e}")
|
||
elif cmd == 'list':
|
||
self.list_files()
|
||
elif cmd == 'ping':
|
||
self.ping()
|
||
elif cmd == 'msg':
|
||
message = parts[1] if len(parts) > 1 else "Hello Server!"
|
||
self.send_message(message)
|
||
else:
|
||
print(f"❌ 未知命令: {cmd}")
|
||
|
||
print() # 空行分隔
|
||
|
||
except KeyboardInterrupt:
|
||
break
|
||
except Exception as e:
|
||
print(f"❌ 命令执行错误: {e}")
|
||
|
||
print("👋 退出交互模式")
|
||
|
||
def test_client():
|
||
"""测试客户端功能"""
|
||
client = JSONSocketClient()
|
||
|
||
print("🧪 开始测试客户端...")
|
||
|
||
# 连接服务器
|
||
if not client.connect():
|
||
return
|
||
|
||
try:
|
||
# 测试 1: Ping
|
||
print("\n--- 测试 1: Ping ---")
|
||
client.ping()
|
||
|
||
# 测试 2: 列出文件
|
||
print("\n--- 测试 2: 列出文件 ---")
|
||
client.list_files()
|
||
|
||
# 测试 3: 获取文件
|
||
print("\n--- 测试 3: 获取文件 ---")
|
||
client.get_file('test_data.json')
|
||
|
||
# 测试 4: 保存文件
|
||
print("\n--- 测试 4: 保存文件 ---")
|
||
test_content = {
|
||
"message": "这是客户端测试数据",
|
||
"timestamp": datetime.now().isoformat(),
|
||
"data": {
|
||
"name": "测试用户",
|
||
"age": 25,
|
||
"hobbies": ["编程", "音乐", "阅读"]
|
||
}
|
||
}
|
||
client.save_file('client_test.json', test_content)
|
||
|
||
# 测试 5: 发送普通消息
|
||
print("\n--- 测试 5: 发送普通消息 ---")
|
||
client.send_message("Hello Server! This is a test message.")
|
||
|
||
print("\n✅ 所有测试完成!")
|
||
|
||
finally:
|
||
client.disconnect()
|
||
|
||
if __name__ == "__main__":
|
||
import sys
|
||
|
||
if len(sys.argv) > 1 and sys.argv[1] == 'test':
|
||
# 运行测试
|
||
test_client()
|
||
else:
|
||
# 交互模式
|
||
client = JSONSocketClient()
|
||
if client.connect():
|
||
try:
|
||
client.interactive_mode()
|
||
finally:
|
||
client.disconnect() |