我有ipaddress列表。我正在使用udp协议将请求异步发送到这些地址到snmp代理。这些地址上的可用snmp代理回复。当我使用这些地址调用BeginSendTo时,设备将以随机顺序进行回复。调用ReceiveBeginReceiveFrom并构造stateobject对象时。 T RemoteIPEndPoint不属于所答复的计算机,而是属于其他计算机。我调用BeginSendTo的方法是否正确?如果是,则y stateobject实例没有给我正确的远程端点?我正在发布我的代码。如果缺少某些内容,请更正。
public class Test
{
Socket udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
class StateObject
{
public Socket Socket { get; set; }
public byte[] DataBuff { get; set; }
public IPEndPoint RemoteEndPoint { get; set; }
//validation are omited
public static StateObject Create(Socket s,byte[] dataBuf,IPEndPoint endpoint)
{
return new StateObject() { Socket = s, DataBuff = dataBuf, RemoteEndPoint = endpoint };
}
public static StateObject Transform(object objectstate)
{
return objectstate as StateObject;
}
}
public void Fx()
{
//list of ip address from 190.188.191.1 - 190.188.191.100
var address = new[] {
IPAddress.Parse("190.188.191.1"),
IPAddress.Parse("190.188.191.100")
};
byte[] dataGram = new byte[1024];
foreach (IPAddress item in address)
{
udpSocket.BeginSendTo(dataGram,
0,
dataGram.Length,
SocketFlags.None,
new IPEndPoint(item, 161),
SendComplete,
StateObject.Create(udpSocket, null, new IPEndPoint(item, 161))
);
}
}
private void SendComplete(IAsyncResult ar)
{
StateObject obj = StateObject.Transform(ar.AsyncState);
obj.Socket.EndSendTo(ar);//ignore the no of bytes send for now
byte[] receivedBytes = new byte[1024 * 4];//assume 4kb is enough for response
var ep = obj.RemoteEndPoint as EndPoint;
obj.Socket.BeginReceiveFrom(receivedBytes,
0,
receivedBytes.Length,
SocketFlags.None,
ref ep,
ReceivedData,
StateObject.Create(obj.Socket, receivedBytes, obj.RemoteEndPoint)
);
}
private void ReceivedData(IAsyncResult ar)
{
StateObject obj = StateObject.Transform(ar.AsyncState);
var ep = obj.RemoteEndPoint as EndPoint;
//response received from ip 190.188.191.2 but in stateobject.remoteendpoint will give 190.188.191.1
var bytesReceived = obj.Socket.EndReceiveFrom(ar,ref ep);
byte[] data = new byte[bytesReceived];
Array.Copy(obj.DataBuff,data, bytesReceived);
}
}
最后,我想出了解决多个udp请求的方法。在状态类型中引入的新字段称为“ ID”。生成ip地址时,会生成一个唯一的标识符。该标识符分配给State Type实例并进行缓存。此ID也在请求中发送,以便识别来自特定IP地址的响应并从其缓存中检索其状态值。
Socket udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
Dictionary<int, StateObject> _Cache = new Dictionary<int, StateObject>();
class StateObject
{
public int ID { get; set; }//uniquely identify the response
public Socket Socket { get; set; }
public byte[] DataBuff { get; set; }
public IPEndPoint RemoteEndPoint { get; set; }
//validation are omited
public static StateObject Create(Socket s, byte[] dataBuf, IPEndPoint endpoint)
{
return new StateObject() { Socket = s, DataBuff = dataBuf, RemoteEndPoint = endpoint };
}
public static StateObject Transform(object objectstate)
{
return objectstate as StateObject;
}
}
//This function is used to generate range of address and corresponding identifiers
IEnumerable<KeyValuePair<IPAddress, int>> GenerateMaps(IPAddress start, IPAddress end)
{
int count = -1;
yield return new KeyValuePair<IPAddress, int>(start, ++count);
//other address in the range
yield return new KeyValuePair<IPAddress, int>(end, ++count);
}
也不是从特定的主机BeginReceiveFrom接收,而是由能够接收和托管的BeginReceive函数代替。标识符映射有助于解决缓存中的问题。