首页 > 解决方案 > Raspberry Pi 与 Win10 IoT 和 Xamarin Android 应用程序之间的 TCP 通信

问题描述

我正在尝试在带有 Win 10 IoT 的 Raspberry Pi 3 和使用 Xamarin Android 开发的应用程序之间开发一个简单的 TCP 服务器/客户端。我正在使用我的三星 S9+ 来调试应用程序。服务器是树莓派。

在覆盆子中,我放了以下代码:

protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        this.StartServer();
    }

    private async void StartServer()
    {
        try
        {
            //Create a StreamSocketListener to start 
            //listening for TCP connections.
            Windows.Networking.Sockets.StreamSocketListener socketListener = new Windows.Networking.Sockets.StreamSocketListener();

            //Hook up an event handler to call when connections are received.
            socketListener.ConnectionReceived += SocketListener_ConnectionReceived;

            //Start listening for incoming TCP connections on the specified port. You can specify any port that's not currently in use.
            await socketListener.BindEndpointAsync(new Windows.Networking.HostName("localhost"),"9999");

        }
        catch (Exception e)
        {
            Debug.WriteLine(e.Message);
        }
    }

    private async void socketListener_ConnectionReceived(Windows.Networking.Sockets.StreamSocketListener sender, Windows.Networking.Sockets.StreamSocketListenerConnectionReceivedEventArgs args)
    {
        //Read line from the remote client.
        Stream inStream = args.Socket.InputStream.AsStreamForRead();
        StreamReader reader = new StreamReader(inStream);
        string request = await reader.ReadLineAsync();

        //Send the line back to the remote client.
        Stream outStream = args.Socket.OutputStream.AsStreamForWrite();
        StreamWriter writer = new StreamWriter(outStream);
        await writer.WriteLineAsync(request);
        await writer.FlushAsync();
    }

在 Xamarin 应用程序中,我有这个:

public class MainActivity : AppCompatActivity
{

    EditText txtInvia;

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        // Set our view from the "main" layout resource
        SetContentView(Resource.Layout.activity_main);
        Button btnInvia = FindViewById<Button>(Resource.Id.btnInvia);
        Button btnConnetti = FindViewById<Button>(Resource.Id.btnConnetti);
        txtInvia = FindViewById<EditText>(Resource.Id.txtInvia);

        btnConnetti.Click += BtnConnetti_Click;
        btnInvia.Click += BtnInvia_Click;
    }

    private void BtnInvia_Click(object sender, EventArgs e)
    {
    }

    private void BtnConnetti_Click(object sender, EventArgs e)
    {
        this.StartClient();
    }

    public static bool PING(string ipAddress)
    {
        // Ping's the local machine.
        Ping pingSender = new Ping();
        IPAddress address = IPAddress.Parse(ipAddress);
        PingReply reply = pingSender.Send(address);

        if (reply.Status == IPStatus.Success)
        {
            Console.WriteLine("Address: {0}", reply.Address.ToString());
            Console.WriteLine("RoundTrip time: {0}", reply.RoundtripTime);
            Console.WriteLine("Time to live: {0}", reply.Options.Ttl);
            Console.WriteLine("Don't fragment: {0}", reply.Options.DontFragment);
            Console.WriteLine("Buffer size: {0}", reply.Buffer.Length);
            return true;
        }
        else
        {
            Console.WriteLine(reply.Status);
            return false;
        }
    }

    private const int PortNumber = 9999;
    private void StartClient()
    {
        string localAddr = "192.168.137.1";
        if (PING(localAddr))
        {
            try
            {
                MyClientTask myClientTask = new MyClientTask(localAddr, PortNumber, string.Format(txtInvia.Text + "\r\n"));
                myClientTask.Execute();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

        }
    }

}

MyClientTask 是这样的:

public class MyClientTask : AsyncTask
{

    string dstAddress;
    int dstPort;
    string response = "";
    string msgToServer;

    public MyClientTask(string addr, int port, string msgTo)
    {
        dstAddress = addr;
        dstPort = port;
        msgToServer = msgTo;
    }

    protected override Java.Lang.Object DoInBackground(params Java.Lang.Object[] @params)
    {
        Socket socket = null;
        DataOutputStream dataOutputStream = null;

        try
        {
            socket = new Socket(dstAddress, dstPort);
            dataOutputStream = new DataOutputStream(socket.OutputStream);

            if (msgToServer != null)
            {
                dataOutputStream.WriteBytes(msgToServer);
            }
            ByteArrayOutputStream byteArrayOutputStream =
                    new ByteArrayOutputStream(1024);
            byte[] buffer = new byte[1024];

            int bytesRead;
            System.IO.Stream inputStream = socket.InputStream;

            /*
             * notice:
             * inputStream.read() will block if no data return
             */
            while ((bytesRead = inputStream.Read(buffer)) != -1)
            {
                byteArrayOutputStream.Write(buffer, 0, bytesRead);
                response += byteArrayOutputStream.ToString("UTF-8");
            }

        }
        catch (UnknownHostException e)
        {
            // TODO Auto-generated catch block
            e.PrintStackTrace();
            response = "UnknownHostException: " + e.ToString();
        }
        catch (IOException e)
        {
            // TODO Auto-generated catch block
            e.PrintStackTrace();
            response = "IOException: " + e.ToString();
        }
        finally
        {
            if (socket != null)
            {
                try
                {
                    socket.Close();
                }
                catch (IOException e)
                {
                    // TODO Auto-generated catch block
                    e.PrintStackTrace();
                }
            }
        }
        return null;
    }

}

在 MyClientTask 中,我使用以下指令创建新套接字:

socket = new Socket(dstAddress, dstPort);

如果我将手机连接到 Raspberry 创建的 HotSpot,我会收到此错误

IOException: Java.Net.ConnectException: failed to connect to /192.168.137.175 (port 9999) from /:: (port 37604): connect failed: ECONNREFUSED (Connection refused) ---> Android.Systems.ErrnoException: connect failed: ECONNREFUSED (Connection refused)

如果我在同一个路由器上通过以太网将我的手机连接到 WiFi 和树莓派,Xamarin 应用程序会在创建套接字时保持阻塞,因为它会超时。

我做错了什么?谢谢!<3

编辑:我看到应用程序中覆盆子的 IP 地址是错误的,所以现在是正确的,我的应用程序以与以太网连接相同的方式被阻止。

标签: c#xamarin.androidraspberry-pi3windows-10-iot-core

解决方案


首先,您可以使用BindServiceNameAsync方法而不是BindEndpointAsync方法来不将流量限制到地址或适配器。

其次,您需要对您使用的服务器端口进行防火墙阻止,以下命令可以允许访问。

netsh advfirewall firewall add rule name="Tcp Server Port(9999)" dir=in protocol=TCP localport=9999 action=Allow

最后,您需要指定应用的设备功能Private Networks (Client & Server)应该为 Tcp 服务器启用该功能。

这里有一个 StreamSocket 示例,您可以参考。它展示了如何使用 StreamSocketListener 类创建一个 TCP 套接字来侦听传入的 TCP 连接。


推荐阅读