c# - 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 地址是错误的,所以现在是正确的,我的应用程序以与以太网连接相同的方式被阻止。
解决方案
首先,您可以使用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 连接。
推荐阅读
- excel - 复制命名范围并将其粘贴到另一个工作表中而不覆盖数据
- python - Python:Foursquare API 和请求需要 cookie 和 javascript
- python - 负对数似然的约简参数
- javascript - 如何使用 Google File Picker API 下载文件?
- rendering - RealityKit 如何在运行时创建自定义网格?
- javascript - JavaScript - 比较非常大的对象数组的有效方法
- sqlite - SQLite 可以返回不存在的列的默认值而不是错误吗?
- ansible - 在 Ansible 中的角色内运行具有特定标签的任务
- linux - Tensorflow 在 proto-files 上创建错误
- python - 使用复合键的多列 Python 聚合