Hi friends! Today’s tutorial is about socket programming for the server and client. The server will send video over the UDP socket and text over the TCP sockets to the client. In contrast to previous tutorials, the client will receive the video and text and send the text messages to the server. Imagine if you have a robot in which the server.py code is running, and it is providing you (the client) the video feed and data in the form of text messages. But if you want to control the robot or server, you need to send the control commands or text messages to the robot. So this tutorial is precisely about achieving the same imagination.
If you have followed our previous tutorials on socket programming, you will find it easy to understand and accordingly change it to fulfill your requirements.
Just a reminder to change the ip address 192.168.1.1
according to your server ip in the following codes.
So here is the server side code:
server.py
# This is server code to send video (over UDP) and message frames (over TCP)
import cv2, imutils, socket
import numpy as np
import time
import base64
import threading, wave, pyaudio,pickle,struct
import sys
import queue
import os
# For details visit pyshine.com
q = queue.Queue(maxsize=10)
BUFF_SIZE = 65536
server_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_RCVBUF,BUFF_SIZE)
host_name = socket.gethostname()
host_ip = '192.168.1.1'# socket.gethostbyname(host_name)
print(host_ip)
port = 9699
socket_address = (host_ip,port)
server_socket.bind(socket_address)
print('Listening at:',socket_address)
vid = cv2.VideoCapture(1)
def generate_video():
WIDTH=400
while(vid.isOpened()):
try:
_,frame = vid.read()
frame = imutils.resize(frame,width=WIDTH)
q.put(frame)
except:
os._exit(1)
print('Player closed')
BREAK=True
vid.release()
def send_video():
fps,st,frames_to_count,cnt = (0,0,1,0)
cv2.namedWindow('TRANSMITTING VIDEO')
cv2.moveWindow('TRANSMITTING VIDEO', 10,30)
while True:
msg,client_addr = server_socket.recvfrom(BUFF_SIZE)
print('GOT connection from ',client_addr)
WIDTH=400
while(True):
frame = q.get()
encoded,buffer = cv2.imencode('.jpeg',frame,[cv2.IMWRITE_JPEG_QUALITY,80])
message = base64.b64encode(buffer)
server_socket.sendto(message,client_addr)
frame = cv2.putText(frame,'FPS: '+str(round(fps,1)),(10,40),cv2.FONT_HERSHEY_SIMPLEX,0.7,(0,0,255),2)
cv2.imshow('TRANSMITTING VIDEO', frame)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
os._exit(1)
TS=False
break
def send_message():
s = socket.socket()
s.bind((host_ip, (port-1)))
s.listen(5)
client_socket,addr = s.accept()
cnt=0
while True:
if client_socket:
while True:
print('SERVER TEXT SENDING:')
data = input ()
a = pickle.dumps(data)
message = struct.pack("Q",len(a))+a
client_socket.sendall(message)
cnt+=1
def get_message():
s = socket.socket()
s.bind((host_ip, (port-2)))
s.listen(5)
client_socket,addr = s.accept()
data = b""
payload_size = struct.calcsize("Q")
while True:
try:
while len(data) < payload_size:
packet = client_socket.recv(4*1024) # 4K
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)
print('',end='\n')
print('CLIENT TEXT RECEIVED:',frame,end='\n')
print('SERVER TEXT SENDING:')
except Exception as e:
print(e)
pass
client_socket.close()
print('Audio closed')
t1 = threading.Thread(target=send_message, args=())
t2 = threading.Thread(target=get_message, args=())
t3 = threading.Thread(target=generate_video, args=())
t4 = threading.Thread(target=send_video, args=())
t1.start()
t2.start()
t3.start()
t4.start()
and the client needs this code:
client.py
# Welcome to PyShine
# This is client code to receive video (over UDP) and message frames (over TCP)
import cv2, imutils, socket
import numpy as np
import time, os
import base64
import threading, wave, pyaudio,pickle,struct
# For details visit pyshine.com
BUFF_SIZE = 65536
BREAK = False
client_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
client_socket.setsockopt(socket.SOL_SOCKET,socket.SO_RCVBUF,BUFF_SIZE)
host_name = socket.gethostname()
host_ip = '192.168.1.1'# socket.gethostbyname(host_name)
print(host_ip)
port = 9699
message = b'Hello'
client_socket.sendto(message,(host_ip,port))
def get_message():
# TCP socket
client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
socket_address = (host_ip,port-1)
print('server listening at',socket_address)
client_socket.connect(socket_address)
print("CLIENT CONNECTED TO",socket_address)
data = b""
payload_size = struct.calcsize("Q")
while True:
try:
while len(data) < payload_size:
packet = client_socket.recv(4*1024) # 4K
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)
print('',end='\n')
print('SERVER TEXT RECEIVED:',frame,end='\n')
print('CLIENT TEXT SENDING:')
except:
break
client_socket.close()
print('Audio closed')
os._exit(1)
def send_message():
# create socket
client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
socket_address = (host_ip,port-2)
print('server listening at',socket_address)
client_socket.connect(socket_address)
print("msg send CLIENT CONNECTED TO",socket_address)
while True:
if client_socket:
while (True):
print('CLIENT TEXT SENDING:')
data = input ()
a = pickle.dumps(data)
message = struct.pack("Q",len(a))+a
client_socket.sendall(message)
def get_video():
cv2.namedWindow('RECEIVING VIDEO')
cv2.moveWindow('RECEIVING VIDEO', 10,360)
fps,st,frames_to_count,cnt = (0,0,20,0)
while True:
packet,_ = client_socket.recvfrom(BUFF_SIZE)
data = base64.b64decode(packet,' /')
npdata = np.fromstring(data,dtype=np.uint8)
frame = cv2.imdecode(npdata,1)
frame = cv2.putText(frame,'FPS: '+str(fps),(10,40),cv2.FONT_HERSHEY_SIMPLEX,0.7,(0,0,255),2)
cv2.imshow("RECEIVING VIDEO",frame)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
client_socket.close()
os._exit(1)
break
if cnt == frames_to_count:
try:
fps = round(frames_to_count/(time.time()-st),1)
st=time.time()
cnt=0
except:
pass
cnt+=1
client_socket.close()
cv2.destroyAllWindows()
t1 = threading.Thread(target=get_message, args=())
t2= threading.Thread(target=send_message, args=())
t3 = threading.Thread(target=get_video, args=())
t1.start()
t2.start()
t3.start()
Usage:
First run the server code in a terminal: python3 server.py
Then run the client code in another terminal: python3 client.py
You can enter text to send from the client and server terminal windows to continue the chatting. Replace the input() with your own control/text data accordingly. Hope you got the idea! Cheers and have a nice day!