Raspberry Pi 与 Win10 IoT 和 Xamarin Android 应用程序之间的 TCP 通信
TCP communication between Raspberry Pi with Win10 IoT and a Xamarin Android Application
我正在尝试在使用 Win 10 IoT 的 Raspberry Pi 3 和使用 Xamarin Android 开发的应用程序之间开发一个简单的 TCP server/client。
我正在使用我的三星 S9+ 来调试应用程序。
服务器是树莓派
在 Raspberry 中我放了这段代码:
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);
如果我将 phone 连接到 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)
如果我在同一路由器上通过以太网将我的 phone 连接到 WiFi 和树莓派,Xamarin 应用程序会在创建套接字时保持阻塞状态,因为它会超时。
我做错了什么?
谢谢! <3
编辑:
我看到应用程序中 Raspberry 的 IP 地址是错误的,所以现在是正确的,我的应用程序以与以太网连接相同的方式被阻止。
首先,您可以使用 BindServiceNameAsync 方法而不是 BindEndpointAsync 方法来不限制地址或适配器的流量。
其次,您需要防火墙阻止您使用的服务器端口,以下命令可以允许访问。
netsh advfirewall firewall add rule name="Tcp Server Port(9999)" dir=in protocol=TCP localport=9999 action=Allow
最后,您需要指定应用的 device capabilities。应该为 Tcp 服务器启用 Private Networks (Client & Server)
功能。
有一个StreamSocket示例here您可以参考。它展示了如何使用 StreamSocketListener class 创建 TCP 套接字来侦听传入的 TCP 连接。
我正在尝试在使用 Win 10 IoT 的 Raspberry Pi 3 和使用 Xamarin Android 开发的应用程序之间开发一个简单的 TCP server/client。 我正在使用我的三星 S9+ 来调试应用程序。 服务器是树莓派
在 Raspberry 中我放了这段代码:
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);
如果我将 phone 连接到 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)
如果我在同一路由器上通过以太网将我的 phone 连接到 WiFi 和树莓派,Xamarin 应用程序会在创建套接字时保持阻塞状态,因为它会超时。
我做错了什么? 谢谢! <3
编辑: 我看到应用程序中 Raspberry 的 IP 地址是错误的,所以现在是正确的,我的应用程序以与以太网连接相同的方式被阻止。
首先,您可以使用 BindServiceNameAsync 方法而不是 BindEndpointAsync 方法来不限制地址或适配器的流量。
其次,您需要防火墙阻止您使用的服务器端口,以下命令可以允许访问。
netsh advfirewall firewall add rule name="Tcp Server Port(9999)" dir=in protocol=TCP localport=9999 action=Allow
最后,您需要指定应用的 device capabilities。应该为 Tcp 服务器启用 Private Networks (Client & Server)
功能。
有一个StreamSocket示例here您可以参考。它展示了如何使用 StreamSocketListener class 创建 TCP 套接字来侦听传入的 TCP 连接。