Sending a .mp4 file over sockets in python3 - python-3.x

I am trying to make two small programs; one is a server which will receive mp4 files from a client. The client is just a small program that sends a .mp4 file located in its folder.
I am able to fully send the mp4 file and a file in the same size is created, but for some reason the mp4 gets corrupted or something else goes wrong and I am unable to play the mp4 file in QuickTime player or VLC.
I don't understand this as I am copying all bytes and sending then all in small packets. I would really appreciate some help or some tips.
Server code:
#!/usr/bin/python3
from socket import socket, gethostname
s = socket()
host = gethostname()
port = 3399
s.bind((host, port))
s.listen(5)
n = 0
while True:
print("Listening for connections...")
connection, addr = s.accept()
try:
print("Starting to read bytes..")
buffer = connection.recv(1024)
with open('video_'+str(n), "wb") as video:
n += 1
i = 0
while buffer:
buffer = connection.recv(1024)
video.write(buffer)
print("buffer {0}".format(i))
i += 1
print("Done reading bytes..")
connection.close()
except KeyboardInterrupt:
if connection:
connection.close()
break
s.close()
Client code:
#!/usr/bin/python3
from socket import socket, gethostname, SHUT_WR
s = socket()
host = gethostname()
port = 3399
s.connect((host, port))
print("Sending video..")
with open("test.mp4", "rb") as video:
buffer = video.read()
print(buffer)
s.sendall(buffer)
print("Done sending..")
s.close()

Fix bugs in your server code:
#!/usr/bin/python3
from socket import socket, gethostname
s = socket()
host = gethostname()
port = 3399
s.bind((host, port))
s.listen(5)
n = 0
while True:
print("Listening for connections...")
connection, addr = s.accept()
try:
print("Starting to read bytes..")
buffer = connection.recv(1024)
with open('video_'+str(n)+'.mp4', "wb") as video:
n += 1
i = 0
while buffer:
video.write(buffer)
print("buffer {0}".format(i))
i += 1
buffer = connection.recv(1024)
print("Done reading bytes..")
connection.close()
except KeyboardInterrupt:
if connection:
connection.close()
break
s.close()
fix here:
with open('video_'+str(n)+'.mp4', "wb") as video:
and here:
while buffer:
video.write(buffer)
print("buffer {0}".format(i))
i += 1
buffer = connection.recv(1024)

Related

How do I shutdown a socket properly that is streaming webcam footage?

I am trying to stream my laptops webcam stream to my pc for cv2 manipulation. The stream works but I am not really sure how to go about closing the socket.
I don't have a webcam on my desktop so I wanted to try and stream my laptops webcam over to learn cv2 on the footage. I am new to sockets, I went through the documentation and did a bunch of googling to get this far, even though most of what I now have was copy pasted. I am not really sure where to look to learn how to shut down sockets propery when streaming video data with cv2.
I've tried using with socket.socket( ... ) as s: to close the connection
breaks after the while and try loops, that go into shutdown(socket.SHUT_WR and close() and I've tried terminating the program on both the client and server.
#server.py
import socket
import cv2
import pickle
import struct
def main():
HOST=''
PORT=12397
with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as s:
print('Socket created')
s.bind((HOST,PORT))
print('Socket bind complete')
s.listen(10)
print('Socket now listening')
conn,addr=s.accept()
data = b""
payload_size = struct.calcsize(">L")
while True:
try:
key = cv2.waitKey(20) & 0xFF
while len(data) < payload_size:
data += conn.recv(4096)
if key == ord("q"):
print("Socket closed.")
break
packed_msg_size = data[:payload_size]
data = data[payload_size:]
msg_size = struct.unpack(">L", packed_msg_size)[0]
while len(data) < msg_size:
data += conn.recv(4096)
if key == ord("q"):
print("Socket closed.")
break
frame_data = data[:msg_size]
data = data[msg_size:]
frame=pickle.loads(frame_data, fix_imports=True, encoding="bytes")
frame = cv2.imdecode(frame, cv2.IMREAD_COLOR)
cv2.imshow('ImageWindow',frame)
cv2.waitKey(1)
if key == ord("q"):
print("Socket closed.")
break
except:
cv2.destroyAllWindows()
break
s.shutdown(socket.SHUT_WR)
s.close()
if __name__ == "__main__":
main()
#client.py
import socket
import cv2
import pickle
import struct
def main():
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]
with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as client_socket:
print('Connecting to socket.')
client_socket.connect((ENTER IP HERE, 12397))
connection = client_socket.makefile('wb')
print('Starting stream.')
cam = cv2.VideoCapture(0)
cam.set(3, 320*2);
cam.set(4, 240*2);
frame_time = int((1.0 / 30.0) * 1000.0)
img_counter = 0
while True:
try:
ret, frame = cam.read()
if ret:
result, frame = cv2.imencode('.jpg', frame, encode_param)
data = pickle.dumps(frame, 0)
size = len(data)
client_socket.sendall(struct.pack(">L", size) + data)
img_counter += 1
if cv2.waitKey(frame_time) & 0xFF == ord('q'):
break
else:
break
except KeyboardInterrupt:
break
cam.release()
client_socket.shutdown(socket.SHUT_WR)
client_socket.close()
if __name__ == "__main__":
main()
I want to close the connection by pressing q.
I currently get WinErrors on the server
OSError: [WinError 10038] An operation was attempted on something that is not a socket
and on the client
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
when I (spam) "q" on the server side, it doesn't seem to catch if I just press it once.
That error typically happen if you use the socket after you have closed it.
Now if we take your server, you do something like
with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as s:
... code here ...
s.shutdown(socket.SHUT_WR)
s.close()
That means the shutdown and close calls are done after the socket have already been closed.
You have the same problem in the client program.

How the client can get the server uploaded original file of filename and extension?

Please help me I just a beginner of python and I want to learn this. I have no idea how to get the original filename and extension from the server part.
I try many ways and research but still cannot work it. I have seen many types of example those just can only upload text file with with open('received_file','.txt','wb') as f: in the client part and cannot upload multiple type extension of files. I know because of the '.txt' so just work for text file. I don't how to declare to get multiple extension and original filename. This is my original code.
client
import socket
import os
TCP_IP = 'localhost'
TCP_PORT = 9001
BUFFER_SIZE = 8192
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
#data = s.recv(BUFFER_SIZE)
with open('received_file','.txt','wb') as f:
print ('file opened')
while True:
print('receiving data...')
data = s.recv(BUFFER_SIZE)
print('data=%s', (data))
if not data:
f.close()
print ('file close()')
break
# write data to a file
f.write(data)
print('Successfully get the file')
s.close()
print('connection closed')
Blockquote
server
import socket
from threading import Thread
from socketserver import ThreadingMixIn
import tkinter
import tkinter.filedialog
TCP_IP = 'localhost'
TCP_PORT = 9001
BUFFER_SIZE = 8192
tkinter.Tk().withdraw()
in_path = tkinter.filedialog.askopenfilename( )
class ClientThread(Thread):
def __init__(self,ip,port,sock):
Thread.__init__(self)
self.ip = ip
self.port = port
self.sock = sock
print (" New thread started for "+ip+":"+str(port))
def run(self):
filename= in_path
f = open(filename,'rb')
while True:
l = f.read(BUFFER_SIZE)
while (l):
self.sock.send(l)
l = f.read(BUFFER_SIZE)
if not l:
f.close()
self.sock.close()
break
tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcpsock.bind((TCP_IP, TCP_PORT))
threads = []
while True:
tcpsock.listen(5)
print ("Waiting for incoming connections...")
(conn, (ip,port)) = tcpsock.accept()
print ('Got connection from ', (ip,port))
newthread = ClientThread(ip,port,conn)
newthread.start()
threads.append(newthread)
for t in threads:
t.join()
The output file of name is received_file without the extension.
You need to define a protocol that transmits the filename, then the data. Here's an example that transmits the content of input.txt to the client as the filename output.txt. The client reads the filename, and then writes the data to that filename. I did this simply because the client and server ran on the same computer, and read/write files in the same directory.
server.py
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
filename = 'output.txt'
self.request.sendall(filename.encode() + b'\r\n')
with open('input.txt','rb') as f:
self.request.sendall(f.read())
if __name__ == "__main__":
HOST, PORT = "localhost", 9001
with socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler) as server:
server.serve_forever()
client.py
import socket
import os
SERVER = 'localhost',9001
s = socket.socket()
s.connect(SERVER)
# autoclose f and s when with block is exited.
# makefile treats the socket as a file stream.
# Open in binary mode so the bytes of the file are received as is.
with s,s.makefile('rb') as f:
# The first line is the UTF-8-encoded filename. Strip the line delimiters.
filename = f.readline().rstrip(b'\r\n').decode()
with open(filename,'wb') as out:
out.write(f.read())

python3 tcp client server communication

I want to send an image (.pgm) via TCP as soon as it is written to the ramdisk. For this I'm working with pyinotify and sockets. After the picture is sent I would like to tell the server to stop now.
Everything works fine but the last part gives me following error:
if data.decode('utf-8') == 'stop': UnicodeDecodeError: 'utf-8' codec can't
decode byte 0x88 in position 319: invalid start byte
Client:
import pyinotify
import socket
import traceback
import sys
class ModHandler(pyinotify.ProcessEvent):
def __init__(self, socket, buffer_size):
self.socket = socket
self.buffer_size = buffer_size
def process_IN_CLOSE_WRITE(self, event):
try:
self.socket.send(bytes(event.pathname, encoding='utf-8'))
file = open(event.pathname, "rb")
line = file.read(self.buffer_size)
while(line):
self.socket.send(line)
line = file.read(self.buffer_size)
except Exception:
traceback.print_exc()
finally:
try:
self.socket.send(bytes('stop', encoding='utf-8'))
print("done")
file.close
except Exception:
traceback.print_exc()
class TCPStream():
def __init__(self, ip, port, buffer_size):
self.ip = ip
self.port = port
self.buffer_size = buffer_size
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
self.socket.connect((self.ip, self.port))
except Exception:
traceback.print_exc()
def __del__(self):
try:
self.socket.close()
except Exception:
traceback.print_exc()
stream = TCPStream('127.0.0.1', 5005, 1024)
handler = ModHandler(stream.socket, stream.buffer_size)
wm = pyinotify.WatchManager()
notifier = pyinotify.Notifier(wm, handler)
wd_value = wm.add_watch("/media/ram_disk", pyinotify.IN_CLOSE_WRITE)
if wd_value["/media/ram_disk"] <= 0:
print("can't add watchmanager to the ram_disk... insufficient
authorization? another watchmanager already running?")
sys.exit(0)
notifier.loop()
Server:
import socket
TCP_IP = '127.0.0.1'
TCP_PORT = 5005
BUFFER_SIZE = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(1)
conn, addr = s.accept()
print("connection address: ", addr)
path = conn.recv(BUFFER_SIZE).decode('utf-8')
filename = path.split("/")
with open(filename[3], 'wb') as f:
data = conn.recv(BUFFER_SIZE)
while data:
print("receiving...")
f.write(data)
data = conn.recv(BUFFER_SIZE)
if not data:
break
if data.decode('utf-8') == 'stop':
f.close()
print("done")
break
conn.close()
The goal is to have a constant TCP stream of images written to the ramdisk. Therefore I wanted to communicate via Bytes with the server to tell him what to do. It seems that after the first picture gets transmitted it breaks somehow. Any help is appreciated!
What if four consecutive bytes in your image at the beginning of a buffer happen to match the ASCII (and UTF-8) characters s t o p? Also, how does the receiving side know when the file name ends, and the file data starts?
You should create a binary encoding that frames the various bits of your data. This makes the whole process nicely deterministic. That's often best done with the struct module's pack and unpack methods. Given a file you want to send, client side:
import os
import struct
...
pathname = event.pathname.encode('utf-8') # Encode pathname into bytes
pathname_len = len(pathname)
file = open(event.pathname, "rb")
filesize = os.path.getsize(event.filename) # Get file size
# Encode size of file name, and size of file into a binary header
header_format = struct.Struct("!II")
header = header_format.pack(pathname_len, filesize)
self.socket.sendall(header)
self.socket.sendall(pathname)
while True:
line = file.read(self.buffer_size)
if not line: break # EOF
self.socket.sendall(line)
# (Remove sending of 'stop' from finally block)
Note the use of sendall to ensure that the entire buffer gets sent (it is legal for send to send only part of a buffer but that can result in missing bytes if you don't account for it).
Server side will look something like this:
import struct
...
def recv_exactly(s, buffer_len):
""" This is the converse of sendall """
data = b''
rem_bytes = buffer_len
while rem_bytes > 0:
buf = s.recv(rem_bytes)
if not buf:
raise Exception("Received EOF in middle of block")
data += buf
rem_bytes -= len(buf)
return data
conn, addr = s.accept()
...
header_format = struct.Struct("!II")
# Receive exactly the bytes of the header
header = recv_exactly(conn, header_format.size)
pathname_len, file_len = header_format.unpack(header)
path = recv_exactly(conn, pathname_len)
filename = path.split("/")
...
rem_bytes = file_len
while rem_bytes > 0:
data = conn.recv(min(rem_bytes, BUFFER_SIZE))
if not data:
raise Exception("Received EOF in middle of file")
f.write(data)
rem_bytes -= len(data)
Another important advantage of this model is that you now have a clear notion of the boundary between one file and the next (without having a "signal value" that might appear in the data). The receiver always knows exactly how many bytes remain until the end of the current file, and the sender can simply move on to send a new header, pathname, and file without opening a new connection.

Send HEX command and read back to rfid reader tcp

I have a rfid reader that receive that from serial and TCP. I was having one accepting XML data before as command, but this reader only accept HEX command
I'm using python, I'm not sure how to format the data, I'm able to connect with that script, but no sending nor answer, only a timeout of the remote connection.
Here the documentation of the reader: http://www.chafon.com/Upload/ProductFile/CF-RU5106_160719140435.pdf
Here's my code:
import socket,time,sys
TCP_IP = '192.168.0.238'
TCP_PORT = 7086
BUFFER_SIZE = 20
MESSAGE = b'0x02'
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((TCP_IP, TCP_PORT))
except:
print ('failed ' + TCP_IP + ' down')
sys.exit()
s.sendall(MESSAGE)
while data is None:
data = s.recv(BUFFER_SIZE)
print ("No data, waiting....")
time.sleep(0.5)
print ("Data arrived")
incoming = data.decode('utf-8')
print (incoming)
s.close()

Python UDP client-server with different matching incoming-outgoing ports

Based on the example at http://www.binarytides.com/programming-udp-sockets-in-python/ I modified it to run on python 3 and used two opposed ports on client and server, so replies from each one go to these ports. Here are my examples
Server:
'''
Simple udp socket server
'''
import socket
import sys
HOST = 'localhost'
PORT_IN = 8889 # Arbitrary non-privileged port
PORT_OUT = 8888
# Datagram (udp) socket
try :
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print('Socket created')
except socket.error as e:
print(e)
sys.exit()
# Bind socket to local host and port
try:
s.bind((HOST, PORT_IN))
except socket.error as e:
print(e)
sys.exit()
print('Socket bind complete')
#now keep talking with the client
while 1:
# receive data from client (data, addr)
d = s.recvfrom(1024)
data = d[0]
addr = d[1]
if not data:
break
reply = 'OK...' + str(data)
s.sendto(reply.encode('UTF-8'), ('localhost', PORT_OUT))
print('Message[' + addr[0] + ':' + str(addr[1]) + '] - ' + str(data).strip())
s.close()
Client:
'''
udp socket client
Silver Moon
'''
import socket #for sockets
import sys #for exit
# create dgram udp socket
try:
s1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
except socket.error:
print('Failed to create socket')
sys.exit()
host = 'localhost'
port_out = 8889
port_in = 8888
counter = 0
while(1) :
# msg = b'aoua'
msg = 'aoua' + str(counter)
try :
#Set the whole string
s1.sendto(msg.encode('UTF-8'), (host, port_out))
# receive data from client (data, addr)
s2.bind(('localhost', port_in))
d = s2.recvfrom(1472)
reply = d[0]
addr = d[1]
print('Server reply : ' + str(reply))
except socket.error as e:
print(e)
# sys.exit()
counter += 1
Problem is with the client which cannot receive any response from server and d = s2.recvfrom(1472) hangs with error [WinError 10022] An invalid argument was supplied.
I've noticed a slightly different behaviour with sock.settimeout(seconds), but I really can't figure why. Isn't d = s2.recvfrom(buffer) supposed to wait for incoming data?
What am I missing here?
Damn... Just saw it. Silly mistake. Calling s2.bind(('localhost', port_in)) in Client inside the loop.

Resources