BeginReceiveFrom()是否按客户端处理?我的理解是它的回调是基于ref的端点触发的。你可以同时进行2次OnReceive回调吗? (下面详细列出了我的问题)
我正在尝试创建一个UDP服务器,概述以下内容:
我在一个IT人员有限的当地政府机构工作。我们在全县拥有超过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 Callback来处理数据包。 (这是我认为我的问题正在发生的地方。)问题是只要有一个客户端发送数据包,而服务器正在处理来自该客户端的数据包一切都很好。例如,这是RequestScreenShotPacket的一部分。只要一个客户端一次请求屏幕截图,哪个效果很好。如果服务器在一个过程中接收另一个呼叫会发生什么,它将开始将两个数据包组合在一起,从而产生一半的图像。 (另一半会被破坏,它会显示奇怪的颜色等)Link to Corrupt Image
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个以上的图像时花费很长时间。它开始延迟数据包的进程。
我的问题是,在允许其他用户发送/接收请求的同时处理大数据包进程的最佳方法是什么?
答案 0 :(得分:2)
BeginReceiveFrom()是否按客户端处理?
我认为你对UDP有一个基本的错失假设。
UDP是无连接的,没有“客户端”,只有该数据包的发送者。因此:
将文件传输到客户端PC并启动批处理/静默安装程序(更新/软件)
将导致您在UDP之上重新创建HTTP(或FTP)和TCP(可能非常糟糕)。 UDP适用于广播以及创建TCP连接的额外开销很大的情况。
在你的情况下:
- 管理员可以轻松查看哪些计算机在线。
- 监控远程PC的运行状况
- 下载有关PC的详细信息。
- 将文件传输到客户端PC并启动批处理/静默安装程序(更新/软件)
前三个比WMI好得多(首先使用类Win32_PingStatus
1 ,对于2 nd 和3 rd 以Win32_ComputerSystem
和Win32_OperatingSystem
开头:大多数WMI都与这两项活动有关。)
最后一点:您是否考虑过组策略?
1 这具有易于以编程方式使用的优点 - ping.exe
也可以工作,但您需要启动一个单独的进程,捕获其输出然后解析它。