Как создать пакет UDP, но не отправлять его - PullRequest
7 голосов
/ 25 мая 2011

Это своего рода странный запрос.

У меня есть байтовый массив, который мне нужно отправить через последовательный порт на другое устройство с помощью C #. Однако мне нужно сначала обернуть байтовый массив в пакет udp, но, опять же, он будет отправлен через последовательный порт, а не через udp. Есть ли способ построить пакет udp в виде массива байтов для последующей передачи через последовательный порт?

Я отправлял и получал сообщения с использованием udp раньше, но никогда там, где пакет udp создан, но не отправлен через udp.

Ответы [ 4 ]

5 голосов
/ 25 мая 2011
3 голосов
/ 25 мая 2011

Я собираюсь принять ответ Йохая, так как эта ссылка (и другие страницы на этом сайте) предоставили код для сборки как пакета udp, так и заголовка ip.Для других, пытающихся сделать это, вот код:

Как его назвать:

var udpPacketBytes = UDPPacket.Construct(IPAddress.Parse("1.1.1.1"), 1000, IPAddress.Parse("2.2.2.2"), 6100, payloadBytes);

Класс UDPPacket:

public static class UDPPacket
    {
        public static byte[] Construct(IPAddress sourceAddress, ushort sourcePort, IPAddress destinationAddress, ushort destinationPort, byte[] payload)
        {
            var bindAddress = IPAddress.Any;

            // Make sure parameters are consistent
            //if ((sourceAddress.AddressFamily != destinationAddress.AddressFamily) || (sourceAddress.AddressFamily != bindAddress.AddressFamily))
            //{
            //    throw new Exception("Source and destination address families don't match!");
            //}

            // Start building the headers
            byte[] builtPacket;
            UdpHeader udpPacket = new UdpHeader();
            ArrayList headerList = new ArrayList();
            //Socket rawSocket = null;
            //SocketOptionLevel socketLevel = SocketOptionLevel.IP;

            // Fill out the UDP header first
            Console.WriteLine("Filling out the UDP header...");
            udpPacket.SourcePort = sourcePort;
            udpPacket.DestinationPort = destinationPort;
            udpPacket.Length = (ushort)(UdpHeader.UdpHeaderLength + payload.Length);
            udpPacket.Checksum = 0;

            if (sourceAddress.AddressFamily == AddressFamily.InterNetwork)
            {
                Ipv4Header ipv4Packet = new Ipv4Header();

                // Build the IPv4 header
                Console.WriteLine("Building the IPv4 header...");
                ipv4Packet.Version = 4;
                ipv4Packet.Protocol = (byte)ProtocolType.Udp;
                ipv4Packet.Ttl = 2;
                ipv4Packet.Offset = 0;
                ipv4Packet.Length = (byte)Ipv4Header.Ipv4HeaderLength;
                ipv4Packet.TotalLength = (ushort)System.Convert.ToUInt16(Ipv4Header.Ipv4HeaderLength + UdpHeader.UdpHeaderLength + payload.Length);
                ipv4Packet.SourceAddress = sourceAddress;
                ipv4Packet.DestinationAddress = destinationAddress;

                // Set the IPv4 header in the UDP header since it is required to calculate the
                //    pseudo header checksum
                Console.WriteLine("Setting the IPv4 header for pseudo header checksum...");
                udpPacket.ipv4PacketHeader = ipv4Packet;

                // Add IPv4 header to list of headers -- headers should be added in th order
                //    they appear in the packet (i.e. IP first then UDP)
                Console.WriteLine("Adding the IPv4 header to the list of header, encapsulating packet...");
                headerList.Add(ipv4Packet);
                //socketLevel = SocketOptionLevel.IP;
            }
            else if (sourceAddress.AddressFamily == AddressFamily.InterNetworkV6)
            {
                Ipv6Header ipv6Packet = new Ipv6Header();

                // Build the IPv6 header
                Console.WriteLine("Building the IPv6 header...");
                ipv6Packet.Version = 6;
                ipv6Packet.TrafficClass = 1;
                ipv6Packet.Flow = 2;
                ipv6Packet.HopLimit = 2;
                ipv6Packet.NextHeader = (byte)ProtocolType.Udp;
                ipv6Packet.PayloadLength = (ushort)(UdpHeader.UdpHeaderLength + payload.Length);
                ipv6Packet.SourceAddress = sourceAddress;
                ipv6Packet.DestinationAddress = destinationAddress;

                // Set the IPv6 header in the UDP header since it is required to calculate the
                //    pseudo header checksum
                Console.WriteLine("Setting the IPv6 header for pseudo header checksum...");
                udpPacket.ipv6PacketHeader = ipv6Packet;

                // Add the IPv6 header to the list of headers - headers should be added in the order
                //    they appear in the packet (i.e. IP first then UDP)
                Console.WriteLine("Adding the IPv6 header to the list of header, encapsulating packet...");
                headerList.Add(ipv6Packet);
                //socketLevel = SocketOptionLevel.IPv6;
            }

            // Add the UDP header to list of headers after the IP header has been added
            Console.WriteLine("Adding the UDP header to the list of header, after IP header...");
            headerList.Add(udpPacket);

            // Convert the header classes into the binary on-the-wire representation
            Console.WriteLine("Converting the header classes into the binary...");
            builtPacket = udpPacket.BuildPacket(headerList, payload);

            /*
            // Create the raw socket for this packet
            Console.WriteLine("Creating the raw socket using Socket()...");
            rawSocket = new Socket(sourceAddress.AddressFamily, SocketType.Raw, ProtocolType.Udp);

            // Bind the socket to the interface specified
            Console.WriteLine("Binding the socket to the specified interface using Bind()...");
            rawSocket.Bind(new IPEndPoint(bindAddress, 0));

            // Set the HeaderIncluded option since we include the IP header
            Console.WriteLine("Setting the HeaderIncluded option for IP header...");
            rawSocket.SetSocketOption(socketLevel, SocketOptionName.HeaderIncluded, 1);

            try
            {
                // Send the packet!
                Console.WriteLine("Sending the packet...");
                int rc = rawSocket.SendTo(builtPacket, new IPEndPoint(destinationAddress, destinationPort));
                Console.WriteLine("send {0} bytes to {1}", rc, destinationAddress.ToString());
            }
            catch (SocketException err)
            {
                Console.WriteLine("Socket error occurred: {0}", err.Message);
                // http://msdn.microsoft.com/en-us/library/ms740668.aspx
            }
            finally
            {
                // Close the socket
                Console.WriteLine("Closing the socket...");
                rawSocket.Close();
            }
            */

            return builtPacket;
        }
    }

Классы протокола: (слишком длинныйразместить здесь)

Код класса протокола

2 голосов
/ 25 мая 2011

Вы должны создать свой пакет UDP, возможно, создав класс UDP, который содержит все данные, содержащиеся в стандартном пакете UDP.

Данные как следует :

Исходный порт [SP] (16 бит) : Когда предпринимается попытка подключения или выполняется соединение, это указывает, какой порт локальный компьютер ожидает для получения ответов от компьютера назначения.

Порт назначения [DP] (16 бит) : Когда пользователь желает подключиться к услуге на удаленной машине, программа прикладного уровня указывает, какой порт следует использовать при первоначальных подключениях. Если он не является частью начального соединения, он указывает, какой номер порта будет использоваться для удаленной машины при отправке пакета по назначению.

Длина [Len] (16 бит) : Это позволяет приемной станции знать, сколько входящих битов должно быть частью действительного пакета. Длина - это подсчет того, сколько байтов является частью пакета UDP, включая байты в заголовке. Поскольку UDP всегда имеет 4 поля в заголовке и каждое имеет 16 бит, а данные / полезная нагрузка переменной длины, мы знаем, что длина будет 8 + (количество байтов в полезной нагрузке.)

Контрольная сумма UDP [UDPCS] (16 бит) : Это контрольная сумма, которая охватывает заголовок и часть данных пакета UDP, чтобы позволить принимающему хосту проверить целостность входящего пакета UDP. Пакет UDP загружается с предварительно определенным номером в поле контрольной суммы, а затем, когда контрольная сумма вычисляется, тогда контрольная сумма записывается поверх предыдущего значения. Когда пакет прибывает в пункт назначения, операционная система целевого устройства просматривает поле заголовка 4 (байты, сделанные из битов с 16 по 31) и извлекает их из пакета, а затем пересчитывает контрольную сумму пакета без каких-либо данных в поле контрольной суммы , Затем ОС сравнивает контрольную сумму, вычисленную с той, которая была передана в пакете. Если контрольная сумма одинакова, с данными все в порядке, и ей разрешено проходить, но если есть разница, UDP-пакет и данные отбрасываются, и принимающая машина не предпринимает попыток получить новый копировать, и отправляющий аппарат не будет пытаться отправить тот же пакет. Пакет потерян навсегда. UDP не надежен! Надежный протокол пакета TCP / IP транспортного уровня см. В пакете TCP.

Данные (переменные биты) : Как и следовало ожидать, это полезная нагрузка или часть данных пакета UDP. Полезной нагрузкой может быть любое количество протоколов (часто прикладного уровня). Некоторые из наиболее часто используемых протоколов UDP включают в себя NFS, DNS, а также несколько протоколов потоковой передачи аудио и видео. Если в UDP-пакете возникает ошибка и ее необходимо исправить, она предоставляется прикладному уровню, чтобы найти ошибку и запросить ее прикладной уровень «порция» или «порция» данных.

Создание класса, который содержит все эти данные и заполняет их соответствующим образом, перегружает ToString, чтобы вы могли затем преобразовать в байтовый массив.

Надеюсь, это поможет.

1 голос
/ 25 мая 2011

Полагаю, причина, по которой я не вижу реальных классов уровня пакета в UdpClient в .NET, заключается в том, что, честно говоря, он очень прост, потому что это протокол без установления соединения / без состояния.

Формат пакета очень простой

bits             0 – 15                   16 – 31
        +-----------------------+-------------------------+
0       | Source Port Number    | Destination Port Number |
        +-----------------------+-------------------------+
32      | Length                | Checksum                |
        +-----------------------+-------------------------+
64      |                                                 |
        |                      Data                       |
        |                                                 |
        +-------------------------------------------------+

Также обратите внимание, что вычисление контрольной суммы действительно имеет немного сложности

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...