LewisChan 技术Blog

今天以物联网网关(网关链接)以服务器,在多个客户端就做一个非常简单的功能:点亮或熄灭网关上的LED灯。目前想到了三种方式,分别是:TCP&UDP测试工具、自编Java客户端和Mono Android客户端。相信这会很有意思的。

1、服务器端

在使用或编写客户端之前,首先来看看服务器端代码,其专门通过串口烧进网关内部

OutputPort led = new OutputPort((Cpu.Pin)GPIO_NAMES.PF8, false);Socket sc;Socket ss = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建tcp套接字IPEndPoint iep = new IPEndPoint(IPAddress.Parse("192.168.13.200"), 8888);//网关IP已静态配置,端口自选try{ss.Bind(iep);ss.Listen(3);Debug.Print("create server ok");}catch{Debug.Print("connection failed");}

然后等待客户端的数据并在终端打印,根据所收信息来判断灯亮灭,最后向客户端发反馈

while (true){if ((sc = ss.Accept()) != null){Debug.Print("someone connected:" + sc.RemoteEndPoint.ToString());while (true){Array.Clear(data, 0, data.Length);//一定要清sc.Receive(data, 16, 0);//从java客户端收到的包括\r\nstring str = new string(System.Text.Encoding.UTF8.GetChars(data));Debug.Print(str);Debug.Print(str.Length.ToString());if (str.IndexOf("ON") >= 0) // = 号不要忽略了{led.Write(true);}else if (str.IndexOf("OFF") >= 0){led.Write(false);}Debug.Print("recv ok,about to send ");sc.Send(System.Text.Encoding.UTF8.GetBytes(str.IndexOf("ON") >= 0 ? "ON\r\n" : "OFF\r\n"));//为方便java中的readline,添加了行结束符}} }

注释的地方基本上是我犯错的地方

2、客户端2.1、TCP&UDP测试工具

测试效果如下:

2.2、Java客户端

代码如下:

public class LightLED {private Socket client;private String host = "192.168.13.200";private int port = 8888;private String on = "ON";private String off = "OFF";public static void main(String[] args) throws InterruptedException,IOException {// TODO Auto-generated method stubnew LightLED().doLED();}public LightLED() throws IOException{client = new Socket(host,port);System.out.println("connected…");}public void doLED() throws IOException,InterruptedException {try {BufferedReader br = getReader(client);PrintWriter pw = getWriter(client);while (true){pw.println(on); //不能用print,为什么?而且发过去的包括\r\nSystem.out.println("LED: " + br.readLine());Thread.sleep(1000);pw.println(off);System.out.println("LED: " + br.readLine());Thread.sleep(1000);}} catch (IOException e) {// TODO: handle exception}}private PrintWriter getWriter(Socket s) throws IOException{OutputStream ous = s.getOutputStream();return new PrintWriter(ous,true);}private BufferedReader getReader(Socket s) throws IOException {InputStream ins = s.getInputStream();return new BufferedReader(new InputStreamReader(ins));}}

VS调试窗口:

Java调试窗口:

2.3、Mono Android客户端

其实用C#也可以写android程序的,并且还可跨平台,也轻松移植到IOS上。它使用的框架是Mono,开发环境是Xamarin,以前叫Mono Develop。网上有很多教程,我在这里就不细说了。我本人的相关软件放在了这里

之前我也没用过mono写过android程序,所以今天是个很好的尝试。事实证明算这一客户端最有趣了,待我细细道来。。

我突然想改变一下前面的想法,由于网关上有3个LED灯,于是这次想让客户端同时操作这3个灯。当我发一个数值时,相应的灯亮或灭。具体细则是这样规定的:我所发送的数值范围是0-7,共8个数,化成二进制恰好可以代表3个灯的状态,1为亮,0为灭,就这样简单定义。而且,为了使得多个android客户端可同时登陆服务器,利用多线程方式来实现。主线程只负责接收客户端连接,每个客户端对应一个单独线程来与服务器通信。

既然这样,服务器端代码就得变了,见下:

首先还是服务器的初使化:

Socket sc = null;Socket ss = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建tcp套接字IPEndPoint iep = new IPEndPoint(IPAddress.Parse("192.168.13.200"), 8888);//网关IP已静态配置,端口自选try{ss.Bind(iep);ss.Listen(5);Debug.Print("create server ok");}catch{Debug.Print("connection failed");}然后无限循环接收客户连接:while (true){byte[] recedata = new byte[1];if ((sc = ss.Accept()) != null){Debug.Print("someone connected:" + sc.RemoteEndPoint.ToString());ClientThread ch = new ClientThread(sc);//创建客户线程类Thread t = new Thread(new ThreadStart(ch.service));t.Start();}}相信已发现上面用到了一个类ClientThread,这是我自定义的:internal class ClientThread{enum GPIO_NAMES{PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PA8, PA9, PA10, PA11, PA12, PA13, PA14, PA15,PB0, PB1, PB2, PB3, PB4, PB5, PB6, PB7, PB8, PB9, PB10, PB11, PB12, PB13, PB14, PB15,PC0, PC1, PC2, PC3, PC4, PC5, PC6, PC7, PC8, PC9, PC10, PC11, PC12, PC13, PC14, PC15,PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7, PD8, PD9, PD10, PD11, PD12, PD13, PD14, PD15,PE0, PE1, PE2, PE3, PE4, PE5, PE6, PE7, PE8, PE9, PE10, PE11, PE12, PE13, PE14, PE15,PF0, PF1, PF2, PF3, PF4, PF5, PF6, PF7, PF8, PF9, PF10, PF11, PF12, PF13, PF14, PF15,PG0, PG1, PG2, PG3, PG4, PG5, PG6, PG7, PG8, PG9, PG10, PG11, PG12, PG13, PG14, PG15};private Socket sc;OutputPort led1 = new OutputPort((Cpu.Pin)GPIO_NAMES.PF8, false);//第一个LEDOutputPort led2 = new OutputPort((Cpu.Pin)GPIO_NAMES.PF7, false);//第二个LEDOutputPort led3 = new OutputPort((Cpu.Pin)GPIO_NAMES.PF6, false);//第三个LEDpublic ClientThread(Socket s){sc = s;//sc.ReceiveTimeout = 60000; // 1分钟内若未收到数据,则关闭连接。由于在虚拟设备中反应很慢,所以就注释掉了}public void service(){byte[] recedata = new byte[1];//目前只接收0-7的某个数try{while (sc.Receive(recedata) != 0){Debug.Print(recedata[0].ToString());doLED(recedata);//根据数值点亮或熄灭灯Array.Clear(recedata,0,1);}}catch (System.Exception ex){sc.Close();Debug.Print("rece timeout" + ex.Message);}}private void doLED(byte[] recedata){//感觉下面写得不太简洁byte L1 = (byte)(recedata[0] >> 2);byte L2 = (byte)((recedata[0] & 3) >> 1);byte L3 = (byte)(recedata[0] & 1);if (L1 == 1){led1.Write(true);}else{led1.Write(false);}if (L2 == 1){led2.Write(true);}else{led2.Write(false);}if (L3 == 1){led3.Write(true);}else{led3.Write(false);}}}好,以上就是修改过的服务器端。下面是用c#写的android客户端。安装好相关软件,打开Xamarin,创建android工程:

相关细节就不详述了,具体可参考官方文档,写得很详细,其实还是用到了android开发的相关概念比如Activity

IDE已经为你生成了相关框架代码,生成了类MainActivity,继承自Activity,重点修改其OnCreate方法,它在界面出现时被调用。

只要有信心,人永远不会挫败

LewisChan 技术Blog

相关文章:

你感兴趣的文章:

标签云: