c# Xamarin UWP/Android 服务器 - 客户端套接字 tcp 无法正确连接

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

我的项目的核心元素是使用套接字通过本地网络在两个应用程序(客户端和服务器)之间进行连接。我学习了很多教程,最稳定的版本是我即将在下面 post 发布的版本。

所以我准备在我的 Xamarin 应用程序上实现它并且有一次(第一次)它起作用了。我什至在我的 android 智能手机(作为客户端)和 windows 上的 UWP(作为服务器)上测试过它。第一次之后,它再也没有用过。既不在我的台式机上,也不在我的笔记本电脑上。我几乎什么也没做,它就停止工作了。

在我第一次接触套接字和 Xamarin 时,我认为它根本不起作用。但是在那一个工作时间之后。一定不是那样的。

疑难解答

我在 ClientSocket.Connect -> _socket.BeginConnect = false

上获取客户端 类 ( ClientSocket )
  1. 我检查了防火墙,卸载并禁用了 防火墙
  2. 我检查了清单,甚至在 ( must-have permissions ) 我尝试启用所有权限。

我会尝试上传一个保管箱link(用于我的文件)

服务器代码 :

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

我的服务器类:

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

客户代码:

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

客户类

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

正如@NicoZhi-MSFT 所说,我通过启用 loopback 设法实现了正确的连接。

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

Please check this document to enable this app loop back

我只有 运行 服务器 端的 命令 来自 这个 link 似乎工作得很好。但是通过 Private Network 始终启用。

所以if你可以制作UWP应用程序运行cmd commands 每次 服务器 需要启动 通过设置一个自动任务 (按照上面link的说明)应该没问题。

提示:

UWP 在 运行ning CMD commands 不是很方便,所以 如果需要 任何人都可以通过设置外部 应用程序 运行 or/and ]s 在需要时 在后台

非常感谢