Home > Net >  is payload size of UDP same as length of byte when I send datagram with "sendto"
is payload size of UDP same as length of byte when I send datagram with "sendto"

Time:06-16

I'm making my own protocol, it's Remote Desktop Protocol that based on UDP. I care with low latency and time efficientcy at cost of quality due to resolution.

According this previous question, It said the maximum SAFE payload size of UDP is 508. Does it mean I send 508 bytes every send?

Here is what am I doing:

# RDP server.py
import cv2 as cv
import numpy as np
from time import time
from mss import mss
import pyautogui as pag
import socket

screenSize = pag.size()

# Optimization Config
'''
2160p = (3840, 2160)
1440p = (2560, 1440)
1080p = (1920, 1080)
720p  = (1280, 720)
480p  = (640, 480)
360p  = (480, 360)
240p  = (426, 240)
144p  = (256, 144)
'''
# resolution = screenSize # Uncomment for using server resolution
resolution = (640, 480) # Uncomment for using common resolution
compression = 5 # 100 means no compress, 0 is highest compression!
encodeParam = (int(cv.IMWRITE_JPEG_QUALITY), compression)


# Server Config
addrPortServer = ('0.0.0.0', 20001)
UDPServerSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
UDPServerSocket.bind(addrPortServer)
UDPServerSocket.settimeout(0.5)
payloadSize = 508

monitor = {"top": 0, "left": 0, "width": screenSize[0], "height": screenSize[1]}

receivePeriode = time()

addrPortClient = None

print('RDU Server is running...')
with mss() as sct:
  while True:
    loopTime = time()

    if loopTime - receivePeriode > 3:
      try:
        dataFromClient, addrPortClient = UDPServerSocket.recvfrom(1024)
        if b'shutdown' in dataFromClient:
          print('Shutdown from client!')
          break
      except:
        addrPortClient = None
      receivePeriode = loopTime
      

    if addrPortClient is not None:
      frame = np.asarray(sct.grab(monitor))
      frame = cv.cvtColor(frame, cv.COLOR_BGRA2BGR)
      frame = cv.resize(frame, dsize=resolution)
      isSucceed, encImg = cv.imencode('.jpg', frame, encodeParam)
      bytesToSend = encImg.tobytes()
      for i in range(0, len(bytesToSend), payloadSize):
        UDPServerSocket.sendto(bytesToSend[i:i payloadSize], addrPortClient)
    # print(time() - loopTime)

while for client.py

# RDP client.py
import cv2 as cv
import numpy as np
from time import time
from mss import mss
import pyautogui as pag
import socket

# Client Config
addrPortServer = ('127.0.0.1', 20001)
UDPClientSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
UDPClientSocket.settimeout(1)
payloadSize = 508
recvFromSize = payloadSize * 2

defaultFrame = np.fromfile('./waiting-server.jpg', dtype=np.uint8)
oldBytesFrame = defaultFrame
screenSize = pag.size() # uncomment for full screen
screenSize = (int(screenSize[0]*0.75), int(screenSize[1]*0.75)) # uncomment for windowed mode

sendPeriode = 0

currentDelay = []
avgDelay = 0
updateDelayTime = time()
with mss() as sct:
  while True:
    loopTime = time()

    if loopTime - sendPeriode > 3: 
      UDPClientSocket.sendto(b'?', addrPortServer)
      sendPeriode = loopTime
    bytesFrame = b''
    lenBytesFromServer = payloadSize
    try:
      while lenBytesFromServer == payloadSize:
        bytesFromServer = UDPClientSocket.recvfrom(recvFromSize)[0]
        lenBytesFromServer = len(bytesFromServer)
        bytesFrame  = bytesFromServer
    except:
      bytesFrame = oldBytesFrame

    try:
      frame = cv.imdecode(np.frombuffer(bytesFrame, dtype=np.uint8), 1)
      frame = cv.resize(frame, screenSize)
    except Exception as e:
      print(e)
      frame = cv.imdecode(np.frombuffer(oldBytesFrame, dtype=np.uint8), 1)
      frame = cv.resize(frame, screenSize)

    # FPS Management
    currentDelay.append(time() - loopTime)
    if time() - updateDelayTime > 1:
      avgDelay = sum(currentDelay) / len(currentDelay)
      currentDelay = []
      print(len(bytesFrame))
      updateDelayTime = time()
    frame = cv.putText(frame, 
      text = str(avgDelay), 
      org = (10,40), 
      fontFace = cv.FONT_HERSHEY_SIMPLEX, 
      fontScale = 1, 
      thickness = 2, 
      lineType = cv.LINE_AA,
      color = (0,0,255))

    try:
      cv.imshow('RDU Client', frame)
    except:
      cv.imshow('RDU Client', cv.imdecode(defaultFrame,1))

    if cv.waitKey(1) == ord('q'):
      cv.destroyAllWindows()
      break
      
    oldBytesFrame = bytesFrame

UDPClientSocket.sendto(b'shutdown', addrPortServer)

Focus to sendto in server.py, You can see I call that function and send bytes with length 508, is that previous question mean?

CodePudding user response:

It said the maximum SAFE payload size of UDP is 508. Does it mean I send 508 bytes every send?

I'm not really sure about your question. But you seem to interpret "SAFE payload size" as guaranteed delivery and having other reliability guarantees. This is not the case.

No matter which payload size is used, UDP will be an unreliable protocol which might result in packet loss, packet reordering and packet duplication. Using a larger payload size than "SAFE" increases the problems though, because then datagrams might be split at the IP level into multiple fragments, and a datagram is lost even if a single fragment of it is lost during delivery.

So with UDP you can never assume that all packets are received exactly once and in order - as your code currently does. No packet size will result in UDP being a reliable protocol, so datagram loss, duplication and reordering need to be handled in the code.

(from comment) Yes I know UDP is unreliable protocol that's why I'm using many try-except to handle it.

Try-except does not help at all with packet loss, packet duplication and packet reordering

(from comment) Is 508 bytes actually maximum (like that previous question answer) or it should be 512 bytes?

The theoretical maximum payload size of a UDP datagram in IPv4 is 65507 bytes. It might be even larger with IPv6 jumbograms - see the information about Length in Wikipedia: UDP datagram structure.

But to come from the lower end: the IPv4 standard says that hosts MUST be able to accept datagrams with up to 576 bytes, while with IPv6 this is 1280. Removing the IP and UDP header this results in a "safe" payload size of 508 for IPv4 (max 60 bytes IPv4 header, fixed 8 bytes UDP header) and 1232 for IPv6 (fixed 40 byte IPv6 header, fixed 8 bytes UDP header).

  • Related