Подключение к Xamarin Forms Socket с использованием IPV6-адреса - PullRequest
0 голосов
/ 18 июня 2020

У меня есть пример приложения Socket, которое обменивается данными между двумя устройствами, используя IP-адрес и порт. IP-адреса IPV4 нормально работают в приложении, но я не могу получить правильную информацию для IP-адресов IPV6.

Мне кажется, я понимаю, о чем идет речь в этой статье относительно идентификатора зоны для адреса IPV6

https://howdoesinternetwork.com/2013/ipv6-zone-id

и Я также считаю, что понимаю, что здесь говорится в этом документе:

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

т.е. мне нужно использовать удаленный IPV6-адрес с идентификатором зоны локального устройства.

Моя проблема в том, что я не могу понять каков идентификатор зоны (ios, android) локального устройства для адресов IPV6. Я загрузил свой образец кода сервера сокета Xamarin Forms и клиентского кода на GitHub, и его можно найти здесь.

Код сервера: https://github.com/gceaser/AsyncSocket Код клиента: https://github.com/gceaser/AsyncSocketClient

У меня есть IP-адреса и порты, определенные в App.xaml. cs для каждого проекта и переключение в каждом проекте на go туда и обратно между IP V4 и V6. (Вам следует обновить IP-адреса для своей среды, если вы пытаетесь это проверить.) Соединение V4 работает, но я не могу заставить работать соединение V6. Любая помощь будет принята с благодарностью.

ПРИМЕЧАНИЕ. Насколько мне известно, вы не можете запускать клиент и сервер на одной машине windows. Что-то странное в том, что сокеты не могут обмениваться данными таким образом, поскольку у меня есть документ в одном из моих постов на StackOverflow. Таким образом, для проверки запустите сервер в поле Windows, а клиент - в iOS.

ОБНОВЛЕНИЕ: Вот код для подключения серверного сокета:

с использованием системы ; используя

System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xamarin.Forms;
using System.Collections.Generic;

namespace AsyncSocketServer
{
    public class AsynchronousSocketListener
    {
        public static ManualResetEvent allDone = new ManualResetEvent(false);
        public delegate void onMessageReceivedComplete(object sender, string message);
        public delegate void onResponseMessageSent(object sender, string message);
        public static event onMessageReceivedComplete MessageReceivedComplete;
        public static event onResponseMessageSent ResponseMessageSent;
        public AsynchronousSocketListener()
        {
        }

        public async static Task StartListening(IPAddress pobj_IPAddress, int pi_Port)
        {
            try
            {

                //IPAddress ipAddress = IPAddress.Parse(pobj_IPAddress);
                IPEndPoint localEndPoint = new IPEndPoint(pobj_IPAddress, pi_Port);

                Socket listener = new Socket(pobj_IPAddress.AddressFamily,
                    SocketType.Stream, ProtocolType.Tcp);

                // Bind the socket to the local endpoint and listen for incoming connections.  
                listener.Bind(localEndPoint);
                listener.Listen(100);
                //ViewModelObjects.AppSettings.SocketStatus = ge_SocketStatus.e_Listening;
                await Task.Delay(100);

                while (true)
                {
                    // Set the event to nonsignaled state.  
                    allDone.Reset();

                    // Start an asynchronous socket to listen for connections.  
                    Debug.WriteLine("Waiting for a connection on " + pobj_IPAddress + " at port " + pi_Port.ToString() + "...");
                    listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);

                    // Wait until a connection is made before continuing.  
                    allDone.WaitOne();
                }

            }
            catch (Exception e)
            {
                Debug.WriteLine("StartListening Error" + e.ToString());
            }

            Debug.WriteLine("Read To end class");

        }

        public static void AcceptCallback(IAsyncResult ar)
        {
            try
            {
                // Signal the main thread to continue.  
                allDone.Set();

                // Get the socket that handles the client request.  
                Socket listener = (Socket)ar.AsyncState;
                //If we have shut down the socket dont do this.  
                Socket handler = listener.EndAccept(ar);

                // Create the state object.  
                StateObject state = new StateObject();
                state.workSocket = handler;
                handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);

            }
            catch (Exception e)
            {
                Debug.WriteLine("AcceptCallback Error" + e.ToString());
            }
        }

        public static void ReadCallback(IAsyncResult ar)
        {
            try
            {
                string ls_ReceivedCommunicationContent = string.Empty;
                string ls_ReturnCommunicationContent = string.Empty;
                //string content = string.Empty;

                // Retrieve the state object and the handler socket  
                // from the asynchronous state object.  
                StateObject state = (StateObject)ar.AsyncState;
                Socket handler = state.workSocket;

                // Read data from the client socket.   
                int bytesRead = handler.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));

                    // Check for end-of-file tag. If it is not there, read   
                    // more data.  
                    ls_ReceivedCommunicationContent = state.sb.ToString();
                    if (ls_ReceivedCommunicationContent.IndexOf("<EOF>") > -1)
                    {
                        //We need to take off the end of file marker
                        string ls_WorkContent = ls_ReceivedCommunicationContent.Replace("<EOF>", "");

                        ls_ReturnCommunicationContent = ls_WorkContent;

                        //Different than app
                        Device.BeginInvokeOnMainThread(() => {
                            MessageReceivedComplete(null, ls_WorkContent);
                        });

                        Send(handler, ls_ReturnCommunicationContent);
                    }
                    else
                    {
                        // Not all data received. Get more.  
                        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                        new AsyncCallback(ReadCallback), state);
                    }
                }
            }
            catch (Exception e)
            {
                Debug.WriteLine("ReadCallback Error" + e.ToString());
            }
        }

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

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

                Device.BeginInvokeOnMainThread(() => {
                    ResponseMessageSent(null, data);
                });

            }
            catch (Exception e)
            {
                Debug.WriteLine("Send Error" + e.ToString());
            }
        }

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

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

                handler.Shutdown(SocketShutdown.Both);
                handler.Close();

            }
            catch (Exception e)
            {
                Debug.WriteLine("SendCallback Error" + e.ToString());
            }
        }
    }
}

Вот код клиента:

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

namespace AsyncSocketClient
{

    // This template use base socket syntax to change Pattern. (like Send, Receive, and so on)
    // Convert to Task-based Asynchronous Pattern. (TAP)
    public static class AsynchronousClientSocket
    {

        public static async Task<string> SendMessage(string ps_IPAddress, int pi_Port, string ps_Message)
        {
            string ls_response = "";

            try
            {
                string ls_ReturnMessage = "";

                // Establish the remote endpoint for the socket.  
                IPAddress ipAddress = IPAddress.Parse(ps_IPAddress);
                IPEndPoint remoteEndPoint = new IPEndPoint(ipAddress, pi_Port);

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

                // Connect to the remote endpoint.  
                var isConnect = await client.ConnectAsync(remoteEndPoint).ConfigureAwait(false);
                if (!isConnect)
                {
                    Console.WriteLine("Can not connect.");
                    return ls_ReturnMessage;
                }

                // Send test data to the remote device. 

                var bytesSent = await client.SendAsync(ps_Message + "<EOF>").ConfigureAwait(false);
                Console.WriteLine("Sent {0} bytes to server.", bytesSent);

                // Receive the response from the remote device.  
                ls_response = await client.ReceiveAsync().ConfigureAwait(false);

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

                // Release the socket.  
                client.Shutdown(SocketShutdown.Both);
                client.Close();
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Error: " + ex.Message);
            }
            return ls_response;
        }

        private static Task<bool> ConnectAsync(this Socket client, IPEndPoint remoteEndPoint)
        {
            if (client == null) throw new ArgumentNullException(nameof(client));
            if (remoteEndPoint == null) throw new ArgumentNullException(nameof(remoteEndPoint));
            return Task.Run(() => Connect(client, remoteEndPoint));
        }

        private static bool Connect(this Socket client, EndPoint remoteEndPoint)
        {
            if (client == null || remoteEndPoint == null)
                return false;

            try
            {
                client.Connect(remoteEndPoint);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        private static async Task<string> ReceiveAsync(this Socket client, int waitForFirstDelaySeconds = 3)
        {
            if (client == null) throw new ArgumentNullException(nameof(client));

            // Timeout for wait to receive and prepare data.
            for (var i = 0; i < waitForFirstDelaySeconds; i++)
            {
                if (client.Available > 0)
                    break;
                await Task.Delay(1000).ConfigureAwait(false);
            }
            // return null If data is not available.
            if (client.Available < 1)
                return null;

            // Size of receive buffer.
            const int bufferSize = 1024;
            var buffer = new byte[bufferSize];

            // Get data
            var response = new StringBuilder(bufferSize);
            do
            {
                var size = Math.Min(bufferSize, client.Available);
                await Task.Run(() => client.Receive(buffer)).ConfigureAwait(false);
                response.Append(Encoding.ASCII.GetString(buffer, 0, size));
            } while (client.Available > 0);

            // Return result.
            return response.ToString();
        }

        private static async Task<int> SendAsync(this Socket client, string data)
        {
            var byteData = Encoding.ASCII.GetBytes(data);
            return await SendAsync(client, byteData, 0, byteData.Length, 0).ConfigureAwait(false);
        }

        private static Task<int> SendAsync(this Socket client, byte[] buffer, int offset,
            int size, SocketFlags socketFlags)
        {
            if (client == null) throw new ArgumentNullException(nameof(client));
            return Task.Run(() => client.Send(buffer, offset, size, socketFlags));
        }
    }
}

Когда я запускаю serer, переключаю его на IPV6 и запускаю, я получаю сообщение о том, что он ожидает подключения следующим образом:

Ожидание соединения на fe80 :: cda4: ea52: 29f5: 2c7 c на порту 8080 ...

При запуске клиента переключите его на IPV6 и попытайтесь отправить сообщение, я получаю сообщение об ошибке:

2020-06-19 09: 32: 51.029902-0400 AsyncSocketClient.iOS [33593: 9360848] Не удается подключиться.

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