Короткая версия
Обрабатывает ли BeginReceiveFrom () для каждого клиента? Насколько я понимаю, его обратный вызов был вызван на основе конечной точки, которая была ref. Можете ли вы иметь 2 OnReceive Callbacks, идущих одновременно? (ниже подробно описываются мои проблемы)
Длинная версия
Я пытаюсь создать UDP-сервер, который будет описывать следующее:
- Администраторы могут легко увидеть, какие компьютеры подключены к сети.
- Монитор состояния удаленных ПК
- Скачать подробную информацию о ПК.
- Передача файлов на клиентские ПК и запуск пакетных / автоматических установщиков (Обновления / Программное обеспечение)
Я работаю в местном правительственном агентстве с ограниченным ИТ-персоналом. У нас более 300+ компьютеров по всему округу. Эти компьютеры варьируются от мили до 25 миль. Это мой метод, помогающий нам легко следить за состоянием компьютеров и обновлять процессы. Во всяком случае ..
Это запуск моего UDP-сервера ...
private static void ServerStart()
{
serv = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint ipe = new IPEndPoint(IPAddress.Any, 55444);
EndPoint ep = (EndPoint)ipe;
serv.Bind(ep);
try
{
LogEvent("Listening...");
serv.BeginReceiveFrom(byteData, 0, byteData.Length, SocketFlags.None, ref ep, new AsyncCallback(initializeConnectionCallback), ep);
}
catch (Exception ex)
{
LogEvent(ex.Message);
}
}
private static void initializeConnectionCallback(IAsyncResult ar)
{
EndPoint epSender = (EndPoint)ar.AsyncState;
serv.EndReceiveFrom(ar, ref epSender);
LoginPacket p = new LoginPacket(byteData);
short opcode = p.getOpcode();
//LogEvent("OPCODE: " + opcode.ToString());
if (!clientList.Exists(element => element.strName == p.clientID))
{
ClientInfo clientInfo = new ClientInfo();
clientInfo.endPoint = epSender;
clientInfo.strName = p.clientID;
clientInfo.isOnline = true;
clientList.Add(clientInfo);
Console.WriteLine("Client: " + clientInfo.strName + " has been added.");
}
else
{
ClientInfo c = clientList.Find(i => i.strName == p.clientID);
c.endPoint = epSender;
c.isOnline = true;
//Console.WriteLine("[Client already active]");
}
ListenForData();
}
private static void ListenForData()
{
EndPoint endpoint = new IPEndPoint(0, 0);
serv.BeginReceiveFrom(byteData, 0, byteData.Length, SocketFlags.None, ref endpoint, new AsyncCallback(OnReceive), endpoint);
}
И довольно большой обратный вызов OnReceive, который обрабатывает пакет. (Вот где я считаю, что мои проблемы возникают.) Проблема в том, что только один клиент отправляет пакет, а сервер обрабатывает пакет с этого одного клиента, все в порядке. Например, это часть RequestScreenShotPacket. Это работает хорошо, если только один клиент запрашивает снимок экрана одновременно. Что произойдет, если сервер получит другой вызов во время процесса одного, он начнет объединять 2 пакета вместе, что приведет к получению половины изображения. (другая половина будет повреждена и будет отображать странные цвета и т. д.) Ссылка на поврежденное изображение
private static void OnReceive(IAsyncResult ar)
{
try
{
EndPoint epSender = (EndPoint)ar.AsyncState;
bool sendBack = true;
serv.EndReceiveFrom(ar, ref epSender);
Packet sendPacket = new Packet();
byte[] message;
short opCode = Packet.parseOpcode(byteData);
sendPacket.insertShort(opCode);
switch (opCode)
{
case PacketHeader.OP_DATA:
{
DataPacket dp = new DataPacket(byteData);
if (dp.DataType == DataPacket.TYPE_REQUESTSCREENSHOT)
{
sendPacket.insertShort(DataPacket.TYPE_REQUESTSCREENSHOT);
LogMessage("Requesting Image...");
RequestScreenPacket rsp = new RequestScreenPacket();
RequestScreenPacket receivedPacket = (RequestScreenPacket)PacketFactory.getPacket(byteData);
rsp.clientID = receivedPacket.clientID;
rsp.computerID = receivedPacket.computerID;
imageTransferList.AddImageTransfer(receivedPacket.clientID, rsp.computerID, 0);
ClientInfo ci = clientList.Find(i => i.strName == receivedPacket.computerID);
rsp.Construct();
sendPacket = (Packet)rsp;
message = sendPacket.Construct();
serv.BeginSendTo(message, 0, message.Length, SocketFlags.None, ci.endPoint, new AsyncCallback(OnSend), ci.endPoint);
sendBack = false;
}
else if (dp.DataType == DataPacket.TYPE_RESPONDSCREENSHOT)
{
sendPacket.insertShort(DataPacket.TYPE_RESPONDSCREENSHOT);
ACKPacket ack = new ACKPacket();
RespondScreenPacket receivedPacket = (RespondScreenPacket)PacketFactory.getPacket(byteData);
ack.ACKTO = receivedPacket.packetFrom;
ack.ACKTYPE = DataPacket.TYPE_IMAGEDATA;
ack.ACKSEQNUM = 0;
ImageTransfer it = imageTransferList.Find(i => i.ImageFrom == receivedPacket.respondTo);
if (it == null)
LogError("Unable to find ImageTransfer in ImageTransferList");
else
it.LastSeqNumber = receivedPacket.lastseqnum;
ClientInfo ci = clientList.Find(i => i.strName == receivedPacket.respondTo);
ack.Construct();
sendPacket = (Packet)ack;
message = sendPacket.Construct();
serv.BeginSendTo(message, 0, message.Length, SocketFlags.None, ci.endPoint, new AsyncCallback(OnSend), ci.endPoint);
sendBack = false;
}
else if (dp.DataType == DataPacket.TYPE_IMAGEDATA)
{
sendPacket.insertShort(DataPacket.TYPE_IMAGEDATA);
ImageDataPacket idp = new ImageDataPacket(byteData);
int seqnum = idp.seqnum + 1;
int offset = idp.offset;
ImageTransfer it = imageTransferList.Find(i => i.ImageFrom == idp.packetFrom);
for (int i = 0; i < idp.block.Length; i++)
{
it.ImageData.Add(idp.block[i]);
}
ACKPacket ack = new ACKPacket();
ack.ACKTYPE = DataPacket.TYPE_IMAGEDATA;
ack.ACKSEQNUM = seqnum;
ClientInfo ci = clientList.Find(i => i.strName == idp.packetFrom);
ack.Construct();
sendPacket = (Packet)ack;
message = sendPacket.Construct();
serv.BeginSendTo(message, 0, message.Length, SocketFlags.None, ci.endPoint, new AsyncCallback(OnSend), ci.endPoint);
if (seqnum >= it.LastSeqNumber)
{
LogMessage("Saving File...");
File.WriteAllBytes(@"C:\\" + it.ImageFrom + ".jpg", it.ImageData.ToArray());
if (imageTransferList.Contains(it))
imageTransferList.Remove(it);
}
sendBack = false;
}
else
{
LogError("UNKNOWN DATAPACKET WITH DATATYPE: " + dp.DataType.ToString());
}
break;
}
case PacketHeader.OP_ACK:
{
sendPacket.insertShort(PacketHeader.OP_ACK);
ACKPacket ackPacket = new ACKPacket(byteData);
if (ackPacket.ACKTYPE == DataPacket.TYPE_IMAGEDATA)
{
}
break;
}
}
message = sendPacket.Construct();
if (sendBack)
{
foreach (ClientInfo c in clientList)
{
if (c.endPoint != null)
{
serv.BeginSendTo(message, 0, message.Length, SocketFlags.None, c.endPoint, new AsyncCallback(OnSend), c.endPoint);
}
}
}
ListenForData();
}
catch (SocketException ex)
{
if (ex.ErrorCode != 10054)
{
LogError(ex.Message);
}
}
catch (Exception ex)
{
LogError(ex.Message);
}
}
Я попытался создать очередь пакетов для обработки пакетов по мере их поступления, но безуспешно. Я чувствую, что именно так я и должен обращаться с очередью, но мои неудачные попытки привели к тому, что очередь пыталась обработать 3+ изображения вплотную. Это начинает задерживать процесс пакетов.
Мой вопрос: как лучше всего обрабатывать большие пакеты, но при этом разрешать другим пользователям отправлять / получать запросы?