I have the following code I am sending the result of intermediate predictions results from the client to server.
Client
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host_name = socket.gethostname() host_ip = 'localhost' print('HOST IP:', host_ip) port = 9999 socket_address = (host_ip, port) server_socket.bind(socket_address) server_socket.listen(5) while True: client_socket, addr = server_socket.accept() print('GOT CONNECTION FROM:', addr) if client_socket: vid = cv2.VideoCapture("D:/testing.mp4") while (vid.isOpened()): img, frame = vid.read() image = img_to_array(frame) image = image.reshape((1, image.shape[0], image.shape[1], image.shape[2])) image = preprocess_input(image) preds = model.predict(image) a = pickle.dumps(preds) message = struct.pack("Q", len(a)) + a client_socket.sendall(message) client_socket.close()
server
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host_ip = 'localhost' port = 9999 client_socket.connect((host_ip, port)) data = b"" payload_size = struct.calcsize("Q") while True: while len(data) < payload_size: packet = client_socket.recv(4 * 1024) if not packet: break data += packet packed_msg_size = data[:payload_size] data = data[payload_size:] msg_size = struct.unpack("Q", packed_msg_size)[0] while len(data) < msg_size: data += client_socket.recv(4 * 1024) frame_data = data[:msg_size] data = data[msg_size:] frame = pickle.loads(frame_data)
While running the above code I am facing the below error
msg_size = struct.unpack(“Q”, packed_msg_size)[0] struct.error: unpack requires a buffer of 8 bytes
Thank you
Advertisement
Answer
You haven’t sorted out normal end of connection. As mentioned in the comments, when the connection is closed by the client, you hit if not packet: break
but that only breaks you out of the inner loop and you keep on trying to process a non-existent message. There is another bug in there where you don’t clear out data
per message.
When nesting loops, especially in communications where end of processing is discovered several steps down, I find it best to break the work into multiple functions with more narrowly defined roles. Here, you want to receive exactly one message at a time, build that into a python object and then use it. 3 functions for three things.
def do_the_things(): client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host_ip = 'localhost' port = 9999 client_socket.connect((host_ip, port)) while True: frame = recv_frame(client_socket) if frame is None: break payload_size = struct.calcsize("Q") def recv_obj(client_socket): data = recvall(client_socket, payload_size) if len(data) < payload_size: if not data: # client closed after last message, assume all is well return None else: raise IOError("Truncated message") packed_msg_size = data[:payload_size] data = data[payload_size:] msg_size = struct.unpack("Q", packed_msg_size)[0] remaining_data = recvall(client_socket, msg_size) if len(remaining_data) < msg_size: raise IOError("Truncated message") obj = pickle.loads(data + remaining_data) return obj def recvall(sock, count): """Keep receiving up to `count` bytes, returning partial result if connection closed normally by remote.""" data_bufs = [] while count: data = sock.recv(count) if not data: break count -= len(data) data_bufs.append(data) return b"".join(data_bufs)