socket通信——多角度控制LED灯亮灭

今天以物联网网关(网关链接)以服务器,在多个客户端就做一个非常简单的功能:点亮或熄灭网关上的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\n
			string 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 stub
		new 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\n
				System.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);//第一个LED
	OutputPort led2 = new OutputPort((Cpu.Pin)GPIO_NAMES.PF7, false);//第二个LED
	OutputPort led3 = new OutputPort((Cpu.Pin)GPIO_NAMES.PF6, false);//第三个LED

	public 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方法,它在界面出现时被调用。

首先创建一些私有量:

private Socket sc = null;
private string host = "192.168.13.200";//服务器端IP和端口
private int port = 8888;

修改OnCreate方法如下:

protected override void OnCreate (Bundle bundle)
{
	base.OnCreate (bundle);
	var layout = new LinearLayout (this);
	layout.Orientation = Orientation.Vertical;

	var lbl = new TextView (this);
	lbl.Text = "hello,xmarin.android";

	sc= new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
	try
	{
		sc.Connect(IPAddress.Parse(host),port);//连接服务器
		lbl.Text = "connected with gateway server";
	}
	catch {
		lbl.Text = "conn failed";
	}

	EditText et = new EditText (this);
	var btn = new Button (this);
	btn.Text = "click and send";
	btn.Click += (sender, e) => {	//添加事件处理
		doLED(et.Text);
	};

	layout.AddView (lbl);
	layout.AddView (et);
	layout.AddView (btn);
	SetContentView (layout);
}

一旦button被点击,执行发送:

public void doLED(string leddata)
{
	byte num = Convert.ToByte (leddata);//获取EditText的数值
	byte[] senddata = new byte[1] {num};
	sc.Send (senddata);
}

最后来一张界面截图:

Yoxi.. 客户端代码就是这样,接下来配置好android模拟器,先在模拟器中跑一跑。在服务器端设一个断点,首先开启服务器,然后再开启Xamarin中的程序。一段时间的等待后(android模拟器启动忒慢),部署程序到模拟器,自动启动了客户端。于是首先在文本框中输入7,使3个灯全亮,见下图:

果然,三灯全亮。再输入4,使第1灯亮,其余二个灯全灭:

最后输入0,不用说,全灭。如果没有反应,可尝试给网关重新上电。

好,最后一招,将客户端部署到android手机。注意,要提前破解Mono for Android,而且不要简简单单地把bin目录中的apk安装到手机中,我试过,不能启动。正确做法是将手机连接PC,安装好驱动后,在IDE中可看到设备:

我在第一次部署到手机时,碰到了这个问题:FastDev directory creation failed。经查询这里有了答案:

https://bugzilla.xamarin.com/show_bug.cgi?id=14474

所以我首先采用release模式部署,再改成debug模式,最后部署成功。

启动android客户端,连上路由器使手机与网关在同一个局域网内。先后输入7,4,0,三灯反应正常:

VS调试窗口如下:

OK,到目前为止,我的目标总算是实现了,能在android跑还是挺欢喜的。逻辑上没问题,至于界面的美化嘛,慢慢修改呗。

其实,又有了个新想法,可创建一个html5 移动web应用,放在手机上运行,应该也可以。那个前端东西我不是很熟悉就不做了,感觉应该也不难。或者这样也可以,以网关为服务器,以Netduino为客户端,通过红外操作netduino,从而控制网关,这样也不错。今天暂搁笔于此,以后有想法再补充。

时间: 2024-12-28 20:25:03

socket通信——多角度控制LED灯亮灭的相关文章

wi-fi-Android 如何通过wifi 控制51单片机led灯亮灭源码

问题描述 Android 如何通过wifi 控制51单片机led灯亮灭源码 请问如何做一个安卓软件控制51单片机led灯的亮灭?有没有人能教我或者给我源码看看 解决方案 串口实现,往wifi透传的方向考虑.看一下这个软件 http://www.wandoujia.com/apps/com.ceacsz.ioe.wifi

lpc1768-用串口接收字符为命令来控制LED灯,该怎么写程序?(LPC1768)

问题描述 用串口接收字符为命令来控制LED灯,该怎么写程序?(LPC1768) 用串口助手发送特定字符来控制LED的亮灭?? 或者给个思路吧!核心的代码写一点也好啊! 有没有大神帮忙把控制部分的程序写下,谢谢啦!刚开始学,请教啊! 解决方案 继电器应该有自己的串口命令吧,你发命令就行了 解决方案二: 买来继电器后 会给你接口的 解决方案三: 单片机接收字符,然后判断,然后使能对应的LED

蓝牙模块控制LED灯的简单程序

问题描述 蓝牙模块控制LED灯的简单程序 怎么实现手机和蓝牙模块的通信,手机发送的值是SBUF吗,直接用就可以吗.我想用数字0控制灯灭,手机只要发送一个0吗,SBUF=0? 解决方案 http://www.dzsc.com/data/2014-9-26/106862.html 解决方案二: 看我博客!有详细说明......

LPC2124--GPIO按键控制LED灯的闪烁

实例目的 实例目的:掌握Proteus软件的使用及调试方法,学习IO编程. 实例内容:  学习使用Proteus.ADS.Keil for ARM软件,掌握绘制原理及编译程序.  键盘输入,当检测到有按键输入时,对发光二极管进行取反控制.使用 I/O口输入方式对按键进行扫描. 实例步骤:  在Proteus中绘制原理图.  在Keil for ARM中输入程序,并编译通过.  加载ELF程序,观察仿真结果.  采用KEIL for ARM与PROTEUS的整合方式联调. 知识点概括

net4 5-C#控制LED灯总算发送是失败

问题描述 C#控制LED灯总算发送是失败 主程序 using LedDemo.Common; using System; using System.Collections.Generic; using System.IO.Ports; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using Syste

android蓝牙如何实现控制led亮灭

问题描述 android蓝牙如何实现控制led亮灭 设计一个安卓软件利用蓝牙通讯来控制硬件电路.最好是低功耗蓝牙,求助各位大神. 解决方案 http://blog.csdn.net/liqinghan/article/details/41346675 解决方案二: 中断控制LED灯亮灭LED的亮灭的判断的实现?

新人求助:android apk直接控制开发板上的4个led灯,实现流水灯

问题描述 新人求助:android apk直接控制开发板上的4个led灯,实现流水灯 在android系统的文件目录下有如下4个文件路径,分别控制4个led亮与灭,写入1亮,0灭 public String path_led1="/sys/devices/platform/leds-gpio/leds/led1/brightness"; public String path_led2="/sys/devices/platform/leds-gpio/leds/led2/bri

FPGA学习之按键控制led

按键控制led 设计要求:通过8个按键分别控制一个led的亮灭.   该实验有两个模块:按键缓存模块和由按键值控制led模块 按键缓存模块:通过二级缓存,将按键值存入key_r1,防止按键时产生的尖峰脉冲影响按键值. 由按键值控制led模块:采用case语句,一一对应控制led的亮灭.   顶层代码: module keyled(clk,rst_n,key,led);   input clk; input rst_n; input [7:0]key; output [7:0]led;   //二

Tiny4412开发板 LED灯的控制

exynos4412裸版控制led灯. 1.查看电路图. 2.查看4412手册.找到对应的寄存器. 3.配置对应的寄存器. 一.再开发板上我们的外部设备led,在核心板.所以我们需要打开核心板电路图.   zshh@HP:~/work/arm/arm资料/exynos4412_lzy/schematic$ lsLCD-HD700-1306.pdf   Tiny4412_1306_core_board_sch.pdfLCD-S701-121212.pdf  Tiny4412SDK_1306_mai