0

I have a sample Socket application that communicates between two devices using and IP address and port. The IPV4 IP-addresses work fine in the application but I cannot seem to get the correct information for the IPV6 IP-addresses.

I believe I understand what is being talked about in this article with regarding to the Zone ID for an IPV6 address

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

and I also believe I understand what is being said here within that document:

If you want to ping a neighbor computer, you will need to specify the neighbor’s IPv6 Link-Local address plus the Zone ID of your computer’s network adapter that is going towards that computer.

i.e. I need to use the remote IPV6 address with the local device's Zone ID.

My problem is I cannot seem to figure out what the local device's (ios, android) Zone ID is for IPV6 addresses. I have uploaded my sample Xamarin Forms socket server and client code to GitHub and it can be accessed here.

Server Code: https://github.com/gceaser/AsyncSocket
Client Code: https://github.com/gceaser/AsyncSocketClient

I have the IP Addresses and ports defined in the App.xaml.cs for each project and a switch in each project to go back and forth between an IP V4 and V6 connection. (You should update the IP addresses for your environment if you are trying to test this.) The V4 connection works but I cannot get the V6 connection to work.

NOTE: To the best of my knowledge you cannot run the client and server on the same Windows machine. Something weird about sockets not being able to communicate that way as I have document in one of my other Stack Overflow post. Thus to test please run the server on a Windows box and the Client within iOS.

Update

Here is the code for the Server Socket connection:

using System;
using 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());
            }
        }
    }
}

Here is the client Code:

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

When I start the serer, switch it to IPV6 and start it, I get the message that it is waiting for a connection as follows:

Waiting for a connection on fe80::cda4:ea52:29f5:2c7c at port 8080...

When I start the Client, switch it to IPV6 and attempt to send a message, I get the error:

2020-06-19 09:32:51.029902-0400 AsyncSocketClient.iOS[33593:9360848] Can not connect.

6
  • please do not post code as links to off-site resources. Please include and format the relevant code within your post Commented Jun 18, 2020 at 21:05
  • Well there is a lot of code. I have found that when I post too much code it seems people don't read the posting as it is too long.. I was trying to get people to read the post hoping they would be able to answer it from the description as I am not sure this problem is specific to my code. Commented Jun 18, 2020 at 22:10
  • you need to do the work to narrow it down to the relevant code Commented Jun 18, 2020 at 22:10
  • I already did. That is what I posted links to. It is a very concise sample. I suggest you llook at it if you haven't already. Commented Jun 18, 2020 at 23:53
  • Are the client and server on the same LAN? Also, different OSes have different ways to express a Zone ID. The RFC leaves it up to the OS, so you need to determine that from the OS where the code is running. Commented Jun 19, 2020 at 13:47

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.