Отправка нескольких Asyn c запросов через сокет в c# - PullRequest
0 голосов
/ 03 апреля 2020

У меня есть список IPaddress. Я использую протокол udp для асинхронной отправки запроса на эти адреса агенту snmp. Доступный агент snmp на эти адреса отвечает. Когда я вызываю BeginSendTo с этими адресами, устройства отвечают в случайном порядке. Когда вызывается ReceiveBeginReceiveFrom и создается объект состояния объекта. T он RemoteIPEndPoint не принадлежит машине, которая ответила, а принадлежит другой машине . Мой подход к вызову BeginSendTo правильный? Если да, то экземпляр объекта состояния не дает мне правильную удаленную точку, которая ответила? Я публикую свой код. Пожалуйста, исправьте, если что-то отсутствует.

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);
    }
}

1 Ответ

0 голосов
/ 09 мая 2020

Наконец-то я понял, что решить эту проблему - разветвлять несколько запросов udp. Новое поле, введенное в State Type, называется «ID». При создании IP-адреса генерируется уникальный идентификатор. Этот идентификатор присваивается экземпляру State Type и кэшируется. Также этот идентификатор отправляется в запросе заказа для идентификации ответа от указанного c 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, которая может принимать и размещать. Отображение идентификатора помогло решить проблему в кеше.

...