C# Функция UdpClient.Receive не возвращается после произвольного числа циклов. - PullRequest
0 голосов
/ 03 февраля 2020

Я работаю над базовым c сетевым заданием для моего класса. Цель состоит в том, чтобы отправить изображение из одной программы в другую через UDP. Обе программы работают на одном и том же P C и могут успешно отправлять друг другу строковые сообщения.

Чтобы отправить изображение, я преобразовываю его из .bmp в байтовый массив с именем ImageBytes, а затем разбиваю этот массив на более мелкие «пакеты» и отправляю их на серверное приложение после отправки количество пакетов для серверного приложения:

public void sendImage(ImageProcessor img)
    {
        int pSize = (Int16.MaxValue / 2);

        int numPackets = img.ImageBytes.Length / pSize;
        int sizeLastPacket = img.ImageBytes.Length % pSize;

        byte[][] packetArr = new byte[numPackets + 1][];

        for (int i = 0; i < numPackets; i++)
        {
            packetArr[i] = new byte[pSize];
        }

        packetArr[numPackets] = new byte[sizeLastPacket];

        for (int i = 0; i < numPackets; i++)
        {
            for (int j = 0; j < pSize; j++)
            {
                packetArr[i][j] = img.ImageBytes[j + pSize * i];
            }
        }

        for (int i = 0; i < sizeLastPacket; i++)
        {
            packetArr[numPackets][i] = img.ImageBytes[numPackets * pSize + i];
        }

        sendDataAsString(numPackets + 1 + "");

        for (int i = 0; i < numPackets; i++)
        {
            sendDataAsBytes(packetArr[i]);
        }

        sendDataAsBytes(packetArr[numPackets]);
    }`

Для контекста ImageProcessor - это класс, который я создал, который содержит член для Image, который я хочу передать, и байтовое представление этого изображения в массиве, ImageBytes.

sendDataAsBytes() - метод, который я написал, который просто вызывает UdpClient.Send(byte[] dgram, int bytes)

sendDataAsString() аналогично, но перед отправкой преобразует из string в byte[].

Вот мой код для получения пакетов:

public byte[] receiveImage(IPEndPoint sourcePoint)
    {
        List<byte> received = new List<byte>();
        byte[] inBuffer;
        int pCount;`

        int.TryParse(receiveDataAsString(sourcePoint), out pCount);

        Console.WriteLine("Number of packets expected: " + pCount);

        for (int i = 0; i < pCount; i++)
        {
            inBuffer = receiveDataAsBytes(sourcePoint);

            Console.WriteLine("Received packet " + (i + 1) + " of " + pCount);
            Console.WriteLine("Waiting for the next one...");

            foreach (var val in inBuffer)
            {
                received.Add(val);
            }
        }

        return received.ToArray();
    }`

Сначала я получаю ожидаемое количество пакетов, а затем вызываю функцию UdpClient.Receive() (завернутую в мой собственный пакет). простая receiveDataAsBytes()) функция в течение 1 oop.

Конкретное изображение, которое я отправляю, разделено на 28 пакетов, однако мое серверное приложение получает только 6 пакетов, и в этот момент оно блокируется функцией UdpClient.Receive(), как будто оно ожидает получения дополнительных данных. быть отправлено. Не возникает никаких исключений, и я не могу понять, почему мое серверное приложение перестает получать в этот момент.

Я попытался отключить брандмауэр Windows безрезультатно, а также протестировал тот же код, отправив несколько пакетов строк. Я отправил 10 пакетов строк, и мое серверное приложение получило их все. Эта проблема возникает как на моем рабочем столе, так и на ноутбуке.

Шаги по коду sendImage() показывают, что все 28 пакетов по крайней мере отправляются, однако я не могу сказать, действительно ли они принимаются receiveImage() или что-то еще проблема.

РЕДАКТИРОВАТЬ: Вот весь код, который у меня есть для клиентского приложения и серверного приложения, соответственно:

using System;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace NetDesignUDPClient
{
    class MyUDPClient
    {
    #region Members    
    public byte[] IpAddr { get; set; }
    public int RecPort { get; set; }
    public int SendPort { get; set; }
    public IPEndPoint RecEndPoint { get; set; }
    public IPEndPoint SendEndPoint { get; set; }
    public UdpClient MyClient { get; set; }
    #endregion

    #region Constructors
    public MyUDPClient()
    {
        IpAddr = new byte[] { 127, 0, 0, 1 };
        RecPort = 1101;
        SendPort = 1100;
        RecEndPoint = new IPEndPoint(new IPAddress(IpAddr), RecPort);
        SendEndPoint = new IPEndPoint(new IPAddress(IpAddr), SendPort);
        MyClient = new UdpClient(RecEndPoint);

        connectToSendPort();
    }
    #endregion

    #region Methods
    public bool connectToSendPort()
    {
        try
        {
            MyClient.Connect(SendEndPoint);
            return true;
        }
        catch (Exception ex)
        {
            // do something
            return false;
        }
    }
    public void sendDataAsString(string usrMsg)
    {
        byte[] sendMsg = Encoding.ASCII.GetBytes(usrMsg);
        sendDataAsBytes(sendMsg);
    }
    public void sendDataAsBytes(byte[] msg)
    {
        MyClient.Send(msg, msg.Length);
    }

    public void sendImage(ImageProcessor img)
    {
        int pSize = (Int16.MaxValue / 2);

        int numPackets = img.ImageBytes.Length / pSize;
        int sizeLastPacket = img.ImageBytes.Length % pSize;

        byte[][] packetArr = new byte[numPackets + 1][];

        for (int i = 0; i < numPackets; i++)
        {
            packetArr[i] = new byte[pSize + 1];
        }

        packetArr[numPackets] = new byte[sizeLastPacket + 1];

        for (int i = 0; i < numPackets; i++)
        {
            packetArr[i][0] = (byte)(i + 1);    // Send packet number

            for (int j = 1; j <= pSize; j++)
            {
                packetArr[i][j] = img.ImageBytes[j + pSize * i];
            }
        }

        for (int i = 0; i < sizeLastPacket; i++)
        {
            packetArr[numPackets][i] = img.ImageBytes[numPackets * pSize + i];
        }

        sendDataAsString(numPackets + 1 + "");

        for (int i = 0; i < numPackets; i++)
        {
            sendDataAsBytes(packetArr[i]);
        }

        sendDataAsBytes(packetArr[numPackets]);
    }

    public string receiveDataAsString(IPEndPoint sourcePoint)
    {
        return Encoding.ASCII.GetString(receiveDataAsBytes(sourcePoint));
    }

    public byte[] receiveDataAsBytes(IPEndPoint sourcePoint)
    {
        return MyClient.Receive(ref sourcePoint);
    }
    #endregion
}
}

Сервер:

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace NetDesignUDPServer
{
class UDPServer
{
    #region Class members    
    public byte[] IpAddr { get; set; }
    public int RecPort { get; set; }
    public int SendPort { get; set; }
    public IPEndPoint RecEndPoint { get; set; }
    public IPEndPoint SendEndPoint { get; set; }
    public UdpClient MyClient { get; set; }
    #endregion

    #region Constructors
    public UDPServer()
    {
        IpAddr = new byte[] { 127, 0, 0, 1 };
        RecPort = 1100;
        SendPort = 1101;
        RecEndPoint = new IPEndPoint(new IPAddress(IpAddr), RecPort);
        SendEndPoint = new IPEndPoint(new IPAddress(IpAddr), SendPort);
        MyClient = new UdpClient(RecEndPoint);


        connectToSendPort();
    }
    #endregion

    #region Methods
    public bool connectToSendPort()
    {
        try
        {
            MyClient.Connect(SendEndPoint);
            return true;
        }
        catch (Exception ex)
        {
            // do something
            return false;
        }
    }

    public string receiveDataAsString(IPEndPoint sourcePoint)
    {
        return Encoding.ASCII.GetString(receiveDataAsBytes(sourcePoint));
    }

    public byte[] receiveDataAsBytes(IPEndPoint sourcePoint)
    {
        return MyClient.Receive(ref sourcePoint);
    }

    public byte[] receiveImage(IPEndPoint sourcePoint)
    {
        List<byte> received = new List<byte>();
        byte[] inBuffer;
        int pCount;

        int.TryParse(receiveDataAsString(sourcePoint), out pCount);

        Console.WriteLine("Number of packets expected: " + pCount);

        for (int i = 0; i < pCount; i++)
        {
            inBuffer = receiveDataAsBytes(sourcePoint);

            Console.WriteLine("Received packet " + inBuffer[0] + " of " + pCount);
            Console.WriteLine("Waiting for the next one...");

            foreach (var val in inBuffer)
            {
                received.Add(val);
            }
        }

        return received.ToArray();
    }

    public void sendDataAsString(string msg)
    {
        byte[] sendMsg = Encoding.ASCII.GetBytes(msg);
        sendDataAsBytes(sendMsg);
    }

    public void sendDataAsBytes(byte[] msg)
    {
        MyClient.Send(msg, msg.Length);
    }

    public void sendImage(ImageProcessor img)
    {
        img.ConvertImageToBytes();

        byte[] val = new byte[1];

        for (int i = 0; i < img.ImageBytes.Length; i++)
        {
            val[0] = img.ImageBytes[i];
            sendDataAsBytes(val);
        }

        val[0] = (byte)' ';
        sendDataAsBytes(val);
    }
    #endregion
}

}

РЕДАКТИРОВАТЬ2: Оказывается, моя проблема была потеря дейтаграмм. Только 6 из ожидаемых 28 дейтаграмм были получены должным образом. Я нашел этот поток и решил попробовать добавить Thread.Sleep() вызовов в мой для l oop. Это привело к решению проблемы с удаленными дейтаграммами за счет задержки в 100 мс между отправками. Я не экспериментировал с более короткими снами, так как скорость не является фактором в этом задании.

...