Вопрос:

Пользовательские заголовки TCP / Копирование заголовка TCP из пакета wireshark

c# sockets asynchronous networking tcp

861 просмотра

1 ответ

6 Репутация автора

Я пытаюсь написать сетевой интерфейс для этой «асинхронной» встроенной карты для светодиодной вывески. Существует существующее программное обеспечение, которое называется «PlutoManager», но оно сделано в Китае, и нашим пожилым клиентам слишком сложно его использовать.

Программное обеспечение делает несколько вещей, взаимодействуя со встроенной картой (называемой PSD100) через кабель Ethernet.

Я посмотрел на некоторую документацию, и в документации говорится, что карта взаимодействует через стандартные протоколы TCP / IP. (Или что-то похожее на TCP / IP, не совсем уверен)

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

(Я не очень хорошо разбираюсь в TCP / IP, поэтому этот перевод может быть грубым, имейте в виду, что эти слова могут быть неправильными, что может быть большой частью моей проблемы.)

Поэтому при каждом обмене данными с картой (отправка файлов, рукопожатия, изменение яркости светодиодного знака и т. Д.) Должны происходить две вещи:

  • Сообщение отправлено на карту (пакет запроса)
  • Ответ получен с карты (пакет ответа)

Структура запроса пакета выглядит следующим образом: (с китайского, и мой перевод отстой)

> 1. Header:  1 byte (16 bits) with a hex value of "0x02" 

 >2. Card Address(??):  2 bytes (32 bits) 
 >3. Packet Type:  2 bytes (32 bits)
 >4. data: indeterminate length
 >5. CRC Check: 2 bytes (32 bits) 
 >6. End of Text Character:  1 byte (16 bits) (value: "0x03" [I guess that's equal to ^c ?]

Похоже ли это на нормальную структуру TCP / IP, прежде чем я увлекся пользовательскими пакетами?

Я подумал, что мог бы использовать Wireshark для перехвата пакетов, отправляемых, когда PlutoManager выполняет рукопожатие. Я также написал некоторый код на C #, пытаясь установить соединение с портом устройства. Вот две стороны рядом. Обратите внимание, что это только часть пакета TCP для дампа, а часть TCP для вывода wireshark - единственная, которая отличается.

TCP SEGMENT CAPTURED FROM WIRESHARK HEX + ASCII DUMP (FROM MY C# CODE)
HEX
0000   d0 6b 7a 43 5e a3 79 62 67 78 dc bf 50 10 80 51        ASCII:    .kzC^.ybgx..P..Q
0010   46 60 00 00                                                F`..

TCP SEGMENT CAPTURED FROM WIRESHARK HEX + ASCII DUMP (PLUTOMANAGER CODE)

HEX
0000   7a 42 d0 6a 34 17 04 36 5e a3 0b 1d 50 10 01 00     ASCII:  zB.j4..6^...P...
0010   82 50 00 00       

Я подумал: «Эй, я могу просто отправить пользовательскую полезную нагрузку на карту с помощью команды Send () и повторить то, что делает код PlutoManager!»

Я не знаю, использует ли это китайское программное обеспечение какую-то особую полезную нагрузку TCP для отправки сообщений на знак или использует стандартный протокол. И я не знаю, как определить разницу. Я пытался использовать Pcap.net для отправки пользовательской полезной нагрузки, но, прежде чем я продолжу заходить так далеко в кроличью нору, кажется ли это необходимым? Является ли второй вывод Wireshark чем-то обычно встречающимся в протоколах TCP / IP? Можно ли просто послать строку "zB / ^ T3mPP" (что является выводом шестнадцатеричного дампа этого рукопожатия), чтобы оно произошло?

Вот как у меня сейчас структурирована моя программа (в основном str:

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;

// State object for receiving data from remote device.
public class StateObject
{
    // Client socket.
    public Socket workSocket = null;
    // Size of receive buffer.
    public const int BufferSize = 256;
    // Receive buffer.
    public byte[] buffer = new byte[BufferSize];
    // Received data string.
    public StringBuilder sb = new StringBuilder();
}

public class AsynchronousClient
{
    // The port number for the remote device.
    private const int port = 31298;

    // ManualResetEvent instances signal completion.
    private static ManualResetEvent connectDone =
        new ManualResetEvent(false);
    private static ManualResetEvent sendDone =
        new ManualResetEvent(false);
    private static ManualResetEvent receiveDone =
        new ManualResetEvent(false);

    // The response from the remote device.
    private static String response = String.Empty;

    private static void StartClient()
    {
        // Connect to a remote device.
        try
        {
            // Establish the remote endpoint for the socket.
            // The name of the 
            // remote device is "host.contoso.com".
            //IPHostEntry ipHostInfo = Dns.Resolve("host.contoso.com");
            IPAddress ipAddress = IPAddress.Parse("192.168.0.59");  //ipHostInfo.AddressList[0];
            IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);

            // Create a TCP/IP socket.
            Socket client = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp);

            // Connect to the remote endpoint.
            client.BeginConnect(remoteEP,
                new AsyncCallback(ConnectCallback), client);
            connectDone.WaitOne();

            // Send test data to the remote device.
            Send(client, "This is a test<EOF>");
            sendDone.WaitOne();

            // Receive the response from the remote device.
            Receive(client);
            receiveDone.WaitOne();

            // Write the response to the console.
            Console.WriteLine("Response received : {0}", response);

            // Release the socket.
            client.Shutdown(SocketShutdown.Both);
            client.Close();

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private static void ConnectCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the socket from the state object.
            Socket client = (Socket)ar.AsyncState;

            // Complete the connection.
            client.EndConnect(ar);

            Console.WriteLine("Socket connected to {0}",
                client.RemoteEndPoint.ToString());

            // Signal that the connection has been made.
            connectDone.Set();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private static void Receive(Socket client)
    {
        try
        {
            // Create the state object.
            StateObject state = new StateObject();
            state.workSocket = client;

            // Begin receiving the data from the remote device.
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReceiveCallback), state);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private static void ReceiveCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the state object and the client socket 
            // from the asynchronous state object.
            StateObject state = (StateObject)ar.AsyncState;
            Socket client = state.workSocket;

            // Read data from the remote device.
            int bytesRead = client.EndReceive(ar);

            if (bytesRead > 0)
            {
                // There might be more data, so store the data received so far.
                state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));

                // Get the rest of the data.
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReceiveCallback), state);
            }
            else
            {
                // All the data has arrived; put it in response.
                if (state.sb.Length > 1)
                {
                    response = state.sb.ToString();
                }
                // Signal that all bytes have been received.
                receiveDone.Set();
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private static void Send(Socket client, String data)
    {
        // Convert the string data to byte data using ASCII encoding.
        byte[] byteData = Encoding.ASCII.GetBytes(data);

        // Begin sending the data to the remote device.
        client.BeginSend(byteData, 0, byteData.Length, 0,
            new AsyncCallback(SendCallback), client);
    }

    private static void SendCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the socket from the state object.
            Socket client = (Socket)ar.AsyncState;

            // Complete sending the data to the remote device.
            int bytesSent = client.EndSend(ar);
            Console.WriteLine("Sent {0} bytes to server.", bytesSent);

            // Signal that all bytes have been sent.
            sendDone.Set();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    public static int Main(String[] args)
    {
        StartClient();
        return 0;
    }
}

Main () запускает команду StartClient (), которая пытается подключиться, но в итоге выдает сообщение об ошибке:

System.Net.Sockets.SocketException (0x80004005): No connection could be made because the target machine actively refused it 192.168.0.59:31298
    at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
    at AsynchronousClient.ConnectCallback(IAsyncResult ar) in C:\Users\xxxxx\Desktop\SocketListenerTest\SocketListenerTest\SocketListenerTest\Program.cs:line 87

Строка 87 это: client.EndConnect(ar);

Это заставляет меня думать, что я подключаюсь к правильному IP и правильному порту, но протокол, который встроен в .NET, и протокол, используемый этим встроенным устройством, отличаются.

У меня есть доступ к китайскому документу (я бы опубликовал его, но он находится под NDA) с некоторыми характеристиками устройства. Если я что-то упустил или вам нужна дополнительная информация из документа, я выложу все, что смогу. Я пытался предоставить наиболее актуальную информацию, какую только мог, но для меня это довольно чуждо.

Я думаю, я мог бы упростить вопрос до «Как я могу изменить метод Sockets.Connect () для использования собственного протокола TCP?» но я подумал, что было бы лучше дать более общий обзор того, что я пытаюсь достичь, потому что это может быть не то, что мне даже нужно делать.

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

Автор: Ryan Alex Martin Источник Размещён: 22.08.2016 09:11

Ответы (1)


0 плюса

192 Репутация автора

Этот ответ может прийти с небольшим опозданием, но SocketExceptionвы получаете ссылку на тот факт, что конечная точка отклоняет все соединение, а не только пользовательскую часть (которая находится в полезной нагрузке).

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

Socket client = new Socket(AddressFamily.InterNetwork,
                           SocketType.Stream,
                           ProtocolType.Tcp);
client.Bind(new IPEndPoint(IPAddress.Any, 32000)); //The port number that PlutoManager uses

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

Автор: Koja Размещён: 27.03.2017 02:14
Вопросы из категории :
32x32