简体   繁体   中英

c# Xamarin UWP/Android server - client socket tcp can't connect properly

The core element of my project is the connection through local network between two applications ( client and server ) using sockets. I've followed many tutorials and the most stable version is the one I am about to post below.

  • I've run it on c# console applications and it works fine
  • I've run it on Windows Forms application and it works fine

So I was ready to implement it on my Xamarin application and for one time ( the first time ) it worked. I've even tested it on my android smartphone ( as client ) and UWP on windows ( as server ). After that first time it never worked again. Neither on my Desktop nor my Laptop. I've literally changed nothing and it stopped working.

At my first touch with sockets and Xamarin I though that it just don't work. But after that one-working time. It must not be that.

TROUBLESHOOTING

I am getting on the client classes ( ClientSocket ) on ClientSocket.Connect -> _socket.BeginConnect = false

  1. I've checked the firewalls, I've uninstalled and disable the firewalls
  2. I've checked the manifest and even there I tried after the ( must-have permissions ) I tried to enable all permissions.

I will try and upload a dropbox link ( for my files )

Server code :

namespace Control
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class HomePage : ContentPage
    {
        public HomePage()
        {
            InitializeComponent();    
        }

        private  void ServerConnectBtn_Clicked(object sender, EventArgs e)
        {
            ServerSocket.Bind(9000);
            ServerSocket.Listen(500);
            ServerSocket.Accept();

            msg_lbl.Text = PacketHandler.status;
        }
    }
}

My server classes:

namespace Control.Server
{
    class ServerSocket
    {
        private static Socket _socket;

        private static byte[] _buffer = new byte[1024];
        public ServerSocket()
        {
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }

        public static void Bind(int port)
        {
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _socket.Bind(new IPEndPoint(IPAddress.Any, port));
        }

        public static void Listen(int backlog)
        {
            _socket.Listen(500);
        }

        public static void Accept()
        {
            _socket.BeginAccept(AcceptedCallback, null);
        }

        private static void AcceptedCallback(IAsyncResult result)
        {
            Socket clientSocket = _socket.EndAccept(result);
            
            _buffer = new byte[1024];
            clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, clientSocket);
            Accept();
        }

        private static void ReceivedCallback(IAsyncResult result)
        {
            Socket clientSocket = result.AsyncState as Socket;

            int bufferSize = clientSocket.EndReceive(result);

            byte[] packet = new byte[bufferSize];
            Array.Copy(_buffer, packet, packet.Length);

            //Handle the packet
            PacketHandler.Handle(packet, clientSocket);


            _buffer = new byte[1024];
            clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, clientSocket);
        }
    }
}

namespace Control.Server
{
    public abstract class PacketStructure
    {
        private byte[] _buffer;
        public PacketStructure(ushort length, ushort type)
        {
            _buffer = new byte[length];
            WriteUshort(length, 0);
            WriteUshort(type, 2);
        }

        public PacketStructure(byte[] packet)
        {
            _buffer = packet;
        }

        public void WriteUshort(ushort value, int offset)
        {
            byte[] tempbuffer = new byte[2];
            tempbuffer = BitConverter.GetBytes(value);
            Buffer.BlockCopy(tempbuffer, 0, _buffer, offset, 2);
        }

        public short ReadUshort(int offset)
        {
            return BitConverter.ToInt16(_buffer, offset);
        }

        public void WriteUint(uint value, int offset)
        {
            byte[] tempbuffer = new byte[4];
            tempbuffer = BitConverter.GetBytes(value);
            Buffer.BlockCopy(tempbuffer, 0, _buffer, offset,4);
        }
        public void WriteString(string value, int offset)
        {
            byte[] tempbuffer = new byte[value.Length];
            tempbuffer = Encoding.UTF8.GetBytes(value);
            Buffer.BlockCopy(tempbuffer, 0, _buffer, offset, value.Length);
        }

        public string ReadString(int offset, int count)
        {
            return Encoding.UTF8.GetString(_buffer, offset, count);
        }

        public byte[] Data {  get { return _buffer; } }
    }
}


namespace Control.Server
{
    public static class PacketHandler
    {
        public static string status;
        public static void Handle(byte[] packet, Socket clientSocket)
        {
            ushort packetLength = BitConverter.ToUInt16(packet, 0);
            ushort packetType = BitConverter.ToUInt16(packet, 2);

            status = "Received packet! Length: "+ packetLength + " | Type: "+ packetType;

            switch (packetType)
            {
                case 2000:
                    Message msg = new Message(packet);
                    Console.WriteLine(msg.Text);
                    break;
            }
        }
    }
}



namespace Control.Server
{
    public class Message : PacketStructure
    {

        private string _message;
        public Message(string message)
            : base((ushort)(4 + message.Length), 2000)
        {
            Text = message;
        }

        public Message(byte[] packet)
            : base(packet)
        {

        }
        public string Text
        {
            get { return ReadString(4, Data.Length - 4); }
            set
            {
                _message = value;
                WriteString(value, 4);
            }
        }
    }
}

Client code:

namespace Remote
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class SettingsPage : ContentPage
    {
        public SettingsPage()
        {
            InitializeComponent();
        }

        private void ClientConnectBtn_Clicked(object sender, EventArgs e)
        {
            ClientSocket.Connect("192.168.1.17",9000);
            Status_lbl.Text = "Status : " +ClientSocket.status;
        }

        private void Send_Clicked(object sender, EventArgs e)
        {
            string msg = msgEntry.Text;
            Message packet = new Message(msg);
            ClientSocket.Send(packet.Data);
            Status_lbl.Text = "Status : " + ClientSocket.status;
        }
    }
}

Client Classes

namespace Remote.Client
{
    public abstract class PacketStructure
    {
        private byte[] _buffer;
        public PacketStructure(ushort length, ushort type)
        {
            _buffer = new byte[length];
            WriteUshort(length, 0);
            WriteUshort(type, 2);
        }

        public PacketStructure(byte[] packet)
        {
            _buffer = packet;
        }

        public void WriteUshort(ushort value, int offset)
        {
            byte[] tempbuffer = new byte[2];
            tempbuffer = BitConverter.GetBytes(value);
            Buffer.BlockCopy(tempbuffer, 0, _buffer, offset, 2);
        }

        public short ReadUshort(int offset)
        {
            return BitConverter.ToInt16(_buffer, offset);
        }

        public void WriteUint(uint value, int offset)
        {
            byte[] tempbuffer = new byte[4];
            tempbuffer = BitConverter.GetBytes(value);
            Buffer.BlockCopy(tempbuffer, 0, _buffer, offset, 4);
        }
        public void WriteString(string value, int offset)
        {
            byte[] tempbuffer = new byte[value.Length];
            tempbuffer = Encoding.UTF8.GetBytes(value);
            Buffer.BlockCopy(tempbuffer, 0, _buffer, offset, value.Length);
        }

        public string ReadString(int offset, int count)
        {
            return Encoding.UTF8.GetString(_buffer, offset, count);
        }

        public byte[] Data { get { return _buffer; } }
    }
}

   
namespace Remote.Client
{
    public class Message : PacketStructure
    {

        private string _message;
        public Message(string message)
            :base((ushort)(4 + message.Length), 2000)
        {
            Text = message;
        }

        public Message(byte[] packet)
            :base(packet)
        {

        }
        public string Text
        {
            get { return ReadString(4, Data.Length - 4); }
            set
            {
                _message = value;
                WriteString(value, 4);
            }
        }
    }
}


namespace Remote.Client
{
    class ClientSocket
    {
        private static Socket _socket;
        private static byte[] _buffer;
        public static string status;

        public ClientSocket()
        {
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }

        public static void Connect(string ipAddress, int port)
        {
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _socket.BeginConnect(new IPEndPoint(IPAddress.Parse(ipAddress), port), ConnectCallback, null);
        }

        private static void ConnectCallback(IAsyncResult result)
        {
            if (_socket.Connected)
            {
                status = "Connected to the server!";
                _buffer = new byte[1024];
                _socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceiveCallback, null);
               // throw new Exception("Conencted");

            }
            else
            {
                
                status = "Could not connect";
              //  throw new Exception("Could not connect");
            }
        }

        private static void ReceiveCallback(IAsyncResult result)
        {
            int bufLength = _socket.EndReceive(result);
            byte[] packet = new byte[bufLength];
            Array.Copy(_buffer, packet, packet.Length);

            //Handle packet

            _buffer = new byte[1024];
            _socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceiveCallback, null);
        }

        public static void Send(byte[] data)
        {
            _socket.Send(data);
        }
    }
}

I managed to achieve the proper connections by enabling loopback as @NicoZhi-MSFT said.

Have you enabled uwp app's loopback and private network capability?

Please check this document to enable this app loop back

I've only ran the commands for the server's side from this link and it seems to be working just fine. But by have Private Network always enabled.

So if you can make the UWP application run cmd commands every time the server needs to start or by settings an automatic task (following the instructions for the link above) it should be ok.

TIP:

UWP is not very handy on running CMD commands so if needed for anyone can look for UWP fulltrust or/and by setting an external application that runs when needed in the background

Many thanks

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM