1. 客户端代码
import json
import time
import struct
import socket
def send_request(sock_obj, method, parameter):
request = json.dumps({"client": method, "params": parameter}) # 请求消息体
length_prefix = struct.pack("I", len(request)) # 请求长度前缀
print("request is {}".format(str.encode(request)))
sock_obj.sendall(length_prefix)
# sock.sendall(request) python2
sock_obj.sendall(str.encode(request)) # python3
def receive_response(sock_obj):
length_prefix = sock_obj.recv(4) # 响应长度前缀
length, = struct.unpack("I", length_prefix)
# print("length is {}".format(length))
body = sock_obj.recv(length) # 响应消息体
res = json.loads(body)
return res # 返回响应
if __name__ == '__main__':
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost", 8080))
for i in range(10):
send_request(s, "func1", "I am {} message".format(i))
response = receive_response(s)
print("response is {}".format(response))
time.sleep(1)
s.close()
2. 服务端代码
import json
import struct
import socket
import threading
def handle_conn(conn, ip, handlers):
print("{} connect ...".format(ip))
# 循环读写
while True:
length_prefix = conn.recv(4) # 请求长度前缀
if not length_prefix: # 连接关闭了
conn.close()
print("{} close ...".format(ip))
break # 退出循环,处理下一个连接
length, = struct.unpack("I", length_prefix)
body = conn.recv(length) # 请求消息体
request = json.loads(body)
client_method = request['client']
client_parameter = request['params']
print("client request method is {}, params is {}".format(client_method, client_parameter))
handler = handlers[client_method] # 查找请求处理器
handler(conn, client_parameter) # 处理请求
def process_request(sock, handlers):
while True:
conn, host_ip = sock.accept() # 接收连接
handle_conn(conn, host_ip, handlers) # 处理连接
def func1(conn, params):
res = json.dumps({"response": "OK", "result": params}) # 响应消息体
length_prefix = struct.pack("I", len(res)) # 响应长度前缀
conn.sendall(length_prefix)
# conn.sendall(response) # python2
conn.sendall(str.encode(res)) # python3
def main():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建一个 TCP 套接字
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 打开 reuse addr 选项
s.bind(("localhost", 8080)) # 绑定端口
s.listen(1) # 监听客户端连接
handlers = {
"func1": func1 # 注册请求处理器
}
# process_request(s, handlers) # 进入服务循环
threads = []
thread_nums = 3
for i in range(thread_nums):
t = threading.Thread(target=process_request, args=(s, handlers))
threads.append(t)
for i in range(thread_nums):
threads[i].start()
for i in range(thread_nums):
threads[i].join()
if __name__ == '__main__':
main()
服务端开了 3 个线程用于处理客户端请求,此时如果客户端数量小于等于 3时,服务端会并行处理,如果客户端数量大于 3 服务端则会阻塞,直到有之前连接的客户端断开,才会继续处理。