Я работаю над базовым 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 мс между отправками. Я не экспериментировал с более короткими снами, так как скорость не является фактором в этом задании.