-
Notifications
You must be signed in to change notification settings - Fork 0
/
socket_helpers.py
executable file
·135 lines (118 loc) · 4.06 KB
/
socket_helpers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/python3
'''
Author: Sam Armstrong
Last updated: 22/2/2018
Desciption:
Some handy functions to make life with sockets in python
a lot easier. No need to worry about the recv() function
disconnecting before the job is through.
Just give the SendMsg(sock,msg) a socket and bytestring
and receive it with RecvMsg(sock).
Image send and receiving has been implemented with jpeg (requires cv2)
and just plain old np arrays.
'''
import socket
import struct
import logging
import numpy as np
try:
import cv2
cv2_found = True
except:
logging.warning("cv2 unable to be imported. JPEG compression not available without opencv installed.")
cv2_found = False
'''
#####################################################################################
Send and receive bytestrings
#####################################################################################
'''
def SendMsg(sock, msg):
'''
Sends an entire byte string.
To be used in conjunction with RecvMsg()
'''
# Prefix each message with a 4-byte length (network byte order)
msg = struct.pack('>I', len(msg)) + msg
sock.sendall(msg)
def RecvMsg(sock):
'''
Receives an ENTIRE message in bytestring.
To be used in conjunction with SendMsg()
'''
# Read message length and unpack it into an integer
raw_msglen = RecvAll(sock, 4)
if not raw_msglen:
return None
msglen = struct.unpack('>I', raw_msglen)[0]
# Read the message data
return RecvAll(sock, msglen)
'''
#####################################################################################
Send and receive images
#####################################################################################
'''
def SendNumpy(sock, nparray, jpeg=False):
'''
Prepares and sends an numpy array over sockets.
@params:
nparray: Numpy array of an image.
jpeg: Enables jpeg compression before sending.
Must be decoded on the receiving end.
'''
if jpeg and cv2_found:
buf = cv2.imencode('.jpg', nparray)[1].tostring()
SendMsg(sock, buf)
else:
# Get the shape of the array to send in header
shape = nparray.shape
dimensions = len(shape)
#Send the number of dimensions, then the sizes.
sock.sendall(struct.pack('>I', dimensions))
# Convert to bytes
for each in shape:
sock.sendall(struct.pack('>I', each))
# Send the actual array
SendMsg(sock, nparray.tostring())
def RecvNumpy(sock, jpeg=False):
'''
Receives an numpy array over sockets.
@params:
sock: The socket to listen on
jpeg: Enables jpeg decompression.
To be enabled if the transmission was compressed.
'''
if jpeg and cv2_found:
buf = np.fromstring(RecvMsg(sock), np.uint8)
nparray = cv2.imdecode(buf, cv2.IMREAD_COLOR)
else:
# Receive header info to rebuild numpy array correctly
num = struct.unpack('>I', RecvAll(sock,4))[0] # Number of dimensions
shape = []
for i in range(num):
shape.append(struct.unpack('>I', RecvAll(sock,4))[0]) # Each dimension
shape = tuple(shape)
# Receive the array
buf = RecvMsg(sock)
logging.debug('Image received. Size: %d %d' % (shape[0], shape[1]))
nparray = np.fromstring(buf, dtype='uint8').reshape(shape)
return nparray
'''
#####################################################################################
Keeps looping until all data is received.
Don't use this function outside, use the better ones
that send heading info instead.
#####################################################################################
'''
def RecvAll(sock, n):
'''
Helper function to recv n bytes or return None if EOF is hit.
'''
data = bytes()
while len(data) < n:
packet = sock.recv(n - len(data))
if not packet:
return None
data += packet
return data
if __name__ == '__main__':
print("No tests defined.")