'Udp image transefing is too slow

I'm trying to send an image from C# to Python side via UDP. I split the image by 1024 bytes and send those chunks. On the Python side - I accept and merge them. The problem is speed. The image, which weighs about 200 KB, takes about 7 seconds to send. I read some questions about similar problems with UDP, but nothing helps. What can I do to speed up this connection? Thanks!
The sample image:
enter image description here

Python side:

import time
import threading
import socket
import traceback
import warnings


class ListenPort:
    def __init__(self, port: int, is_camera: bool = False):
        self.__port = port
        self.__is_camera = is_camera

        self.thread = None
        self.__stop_thread = False
        self.out_string = ""
        self.out_bytes = b""

        self.ip_end_point = ('127.0.0.1', self.__port)
        self.sct = None

    def start_listening(self):
        self.thread = threading.Thread(target=self.listening, args=())
        self.thread.start()

    def listening(self):
        self.sct = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        print("connected: " + str(self.__port))
        while not self.__stop_thread:
            try:
                if self.__is_camera:
                    self.sct.sendto("Wait for size".encode('utf-16-le'), self.ip_end_point)
                    image_size, _ = self.sct.recvfrom(4)
                    print(len(image_size))
                    if len(image_size) < 4:
                        continue
                    buffer_size = (image_size[3] & 0xff) << 24 | (image_size[2] & 0xff) << 16 | \
                                  (image_size[1] & 0xff) << 8 | (image_size[0] & 0xff)
                    self.sct.sendto("Wait for image".encode('utf-16-le'), self.ip_end_point)
                    local_bytes = b""
                    check_iters = 0
                    for i in range(0, buffer_size // 1024):
                        local_bytes += self.sct.recvfrom(1024)[0]
                        self.sct.sendto("Got data".encode('utf-16-le'), self.ip_end_point)
                        check_iters += 1
                        print(check_iters)
                    print(check_iters)
                    if buffer_size % 1024 > 0:
                        local_bytes += self.sct.recvfrom(buffer_size % 1024)[0]
                    self.out_bytes = local_bytes
                else:
                    self.sct.sendto("Wait for data".encode('utf-16-le'), self.ip_end_point)
                    self.out_bytes, _ = self.sct.recvfrom(1024)
                    self.out_string = self.out_bytes.decode('utf-16-le')
            except OSError:
                break
            except (Exception, EOFError):
                traceback.print_exc()
        print("disconnected: " + str(self.__port))

    def reset_out(self):
        self.out_string = ""
        self.out_bytes = b""

    def stop_listening(self):
        self.__stop_thread = True
        self.reset_out()
        if self.sct is not None:
            self.sct.shutdown(socket.SHUT_RDWR)

            if self.thread is not None:
                st_time = time.time()
                while self.thread.is_alive():
                    if time.time() - st_time > 2:
                        warnings.warn("Something went wrong. Rude disconnection on port " + str(self.__port))
                        self.sct.close()
                        st_time = time.time()


listen = ListenPort(63213, True)
listen.start_listening()

st_time = time.time()

while True:
    if len(listen.out_bytes) == 218669:
        print("got image")
        break

print(time.time() - st_time)
listen.stop_listening()

# the out of print(time.time() - st_time) is 7.35678505897522

C# side:

public struct Received
{
    public IPEndPoint Sender;
    public string Message;
}

public abstract class UdpBase
{
    protected UdpClient Client;

    protected UdpBase()
    {
        Client = new UdpClient();
    }

    public async Task<Received> Receive()
    {
        var result = await Client.ReceiveAsync();
        return new Received()
        {
            Message = Encoding.Unicode.GetString(result.Buffer, 0, result.Buffer.Length),
            Sender = result.RemoteEndPoint
        };
    }
}

public class TalkPortUdp : UdpBase
{
    private bool stopTask = false;
    private IPEndPoint _talkOn;

    private string outString = "";
    private byte[] outBytes = new byte[10];

    public IPEndPoint sender;
    public Task task;

    public TalkPortUdp(IPEndPoint endpoint)
    {
        _talkOn = endpoint;
    }

    public void SetString(string data)
    {
        outString = data;
    }

    public void SetBytes(byte[] data)
    {
        outBytes = data;
    }

    public void Send(string message, IPEndPoint endpoint)
    {
        var datagram = Encoding.Unicode.GetBytes(message);
        Client.Send(datagram, datagram.Length, endpoint);
    }

    public void SendBytes(byte[] message, IPEndPoint endpoint)
    {
        Client.Send(message, message.Length, endpoint);
    }

    public void StartTalking()
    {
        Client = new UdpClient(_talkOn);
        stopTask = false;
        task = Task.Run(() => {
            while (!stopTask)
            {
                try
                {
                    if (this.Client.Available > 0)
                    {
                        var received = this.Receive().GetAwaiter().GetResult();
                        string clientTask = received.Message;
                        sender = received.Sender;

                        if (clientTask.Contains("Wait for size"))
                        {
                            byte[] intBytes = BitConverter.GetBytes(outBytes.Length);
                            this.SendBytes(intBytes, received.Sender);
                        }
                        else if (clientTask.Contains("Wait for image"))
                        {
                            for (int i = 0; i < outBytes.Length - 1024; i += 1024)
                            {
                                byte[] second = new byte[1024];
                                Buffer.BlockCopy(outBytes, i, second, 0, 1024);
                                Console.WriteLine(i);
                                this.SendBytes(second, received.Sender);
                                received = this.Receive().GetAwaiter().GetResult();
                            }
                            int lastt = outBytes.Length % 1024;
                            if (lastt > 0)
                            {
                                byte[] lasttBytes = new byte[lastt];
                                Buffer.BlockCopy(outBytes, outBytes.Length - lastt, lasttBytes, 0, lastt);
                                this.SendBytes(lasttBytes, received.Sender);
                            }
                        }
                        else if (clientTask.Contains("Wait for data"))
                        {
                            this.Send(outString, received.Sender);
                        }

                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }
            Console.WriteLine("Stopped");
        });
    }

    public bool IsAlive()
    {
        if (task != null)
            return task.Status.Equals(TaskStatus.Running);
        return false;
    }

    public void StopTalking()
    {
        stopTask = true;
        Client.Dispose();
        Client.Close();
    }
}

internal class Program
{
    static void Main(string[] args)
    {
        IPEndPoint ipPoint = new IPEndPoint(IPAddress.Any, 63213);
        TalkPortUdp talk = new TalkPortUdp(ipPoint);

        talk.StartTalking();
        while (true)
        {
            // Load file meta data with FileInfo
            FileInfo fileInfo = new FileInfo(@"D:\Downloads\test_img.png");

            // The byte[] to save the data in
            byte[] data = new byte[fileInfo.Length];
            // Console.WriteLine(fileInfo.Length);

            // Load a filestream and put its content into the byte[]
            using (FileStream fs = fileInfo.OpenRead())
            {
                fs.Read(data, 0, data.Length);
            }

            talk.SetBytes(data);

            Thread.Sleep(1000);
        }
    }
}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source