智能电视局域网手机遥控实现

        好久没写博客了,今天来写一篇之前实现过的,算是温故而知新吧。

        先说下功能:在局域网内,手机来遥控智能电视,都是基于Android系统的,有些手机自带红外线功能,可以不用网络连接,此处不讨论

        (此文只讨论手机端实现)

       手机与TV之前通过局域网通信,先要建立Socket连接,但手机怎么知道电视的 IP呢?

        解决方案有多种,如果只有一个路由器,可以采用UDP广播来实现,如果跨路由器了,这种方式不可行,因为路由器隔离广播,可以采用遍历扫描指定端口方式

此种采用UDP广播来实现手机找到电视IP地址,另一种方式,可以参照 局域网内扫描打开指定端口IP(请点击我),有时间我再把Android手机扫描指定端口整理下


先说下简单流程:

接下来,上代码

手机发UDP广播:

public void sendData(DatagramSocket ds, byte[] str)
			throws UnknownHostException {
		
		if (ds.isClosed()) {
			return;
		}

		byte[] buf = new byte[1000];
		DatagramPacket packet = new DatagramPacket(buf, buf.length);//
		// 创建要发送的数据包
		DatagramPacket dp = new DatagramPacket(str, str.length,
				InetAddress.getByName("255.255.255.255"),
				NetTools.RECV_BCAST_PORT);
		// 构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号
		try {
			ds.send(dp);
			Log.i(TAG, dp.toString());
			ds.receive(packet);
			String tem = new String(buf);
			Log.i(TAG, "get server string =" + tem);
			NetTools.SERVER_IP = packet.getAddress().getHostAddress();
			Log.i(TAG, "get server ip =" + NetTools.SERVER_IP);
			ds.close();
			ds = null;
			sendBroadcast(new Intent(NetTools.ACTION_FOUND_IP));
			timer.cancel();
			timer = null;

			System.gc();

			stopSelf();

		} catch (IOException e) {
			Log.i(TAG, "IOException");
			// ds.close();
			// stopSelf();
			// Intent mIntent = new Intent(this, NetServer.class);
			// startService(mIntent);
			e.printStackTrace();
		}
		// ds.close();

	}
发UPD广播后,TV收到该广播,返回一个数据包,解析该数据包,获取 TV IP

有了 TV IP,建立Socket进行通信:

class MyReceiver extends BroadcastReceiver {

		public MyReceiver() {
			IntentFilter filter = new IntentFilter();
			filter.addAction(NetTools.ACTION_FOUND_IP);
			registerReceiver(this, filter);
		}

		@Override
		public void onReceive(Context context, Intent intent) {
			// TODO Auto-generated method stub
			tv.setText(NetTools.SERVER_IP);
			if (thread != null) {
				thread = null;
			}
			thread = new ClientThread();
			thread.start();

		}

	}

	// 内部类,新线程
	class ClientThread extends Thread {

		public OutputStream out;
		public InputStream in;

		@Override
		public void run() {
			// 建立连接通道,取出双向流
			try {
				mSocket = new Socket(NetTools.SERVER_IP,
						NetTools.RECV_INFO_PORT);

				mSocket.setKeepAlive(true);
				mSocket.setSoTimeout(NetTools.BACKLOG * 1000);

				out = mSocket.getOutputStream();// 取出双向流
				in = mSocket.getInputStream();

				if (mSocket.isConnected()) {
					NetTools.isAlive = true;
					// tv.setText("mSocket is connect,ip=" +
					// NetTools.SERVER_IP);
					Message msg = Message.obtain(mHandler,
							NetTools.MSG_UP_TEXT, "mSocket is connect,ip="
									+ NetTools.SERVER_IP);
					msg.sendToTarget();

				}

				if (mHeardThread != null) {
					mHeardThread = null;
				}
				mHeardThread = new HeardThread();
				mHeardThread.start();

				byte[] buff = new byte[8];

				while (NetTools.isAlive) {
					sb.delete(0, sb.length());
					try {
						in.read(buff);
						for (int i = 0; i < buff.length; i++) {
							sb.append(buff[i]);
							sb.append(":");
						}
						Message msg = Message.obtain(mHandler,
								NetTools.MSG_UP_TEXT,
								"msocket is alive,get packet:" + sb.toString());
						msg.sendToTarget();

					} catch (IOException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
						Message msg = Message.obtain(mHandler,
								NetTools.MSG_UP_TEXT,
								"Socket read time out,close the socket");
						msg.sendToTarget();

						NetTools.isAlive = false;
						try {
							mSocket.close();
							mHeardThread = null;
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					// try {
					// sleep(NetTools.BACKLOG * 1000);
					// } catch (InterruptedException e) {
					// // TODO Auto-generated catch block
					// e.printStackTrace();
					// }

				}

			} catch (UnknownHostException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e2) {
				// TODO Auto-generated catch block
				e2.printStackTrace();
			}

			Log.i(TAG, "ClientThread stop");
		}
	}

保持心跳,(有些路由器可能会断开长时间没连接的Socket,心跳机制就是为了防止断开的)

class HeardThread extends Thread {
		@Override
		public void run() {
			// TODO Auto-generated method stub
			super.run();
			while (NetTools.isAlive) {

				if (heard_flag) {
					Log.i(TAG, "HeardThread run::sendHeardPacket");
					sendHeardPacket();
					try {
						sleep(NetTools.BACKLOG * 1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				} else {
					Log.i(TAG, "HeardThread sendHeardPacket pause");
					try {
						synchronized (mHeardThread) {
							wait();
						}
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}

			}
			Log.i(TAG, "end heardthread");
		}
	}

遥控操作:

public void doClick(View v) {
		int keyCode = 0;
		switch (v.getId()) {
		case R.id.btn_up: {
			keyCode = KeyEvent.KEYCODE_DPAD_UP;
		}
			break;

		case R.id.btn_down: {
			keyCode = KeyEvent.KEYCODE_DPAD_DOWN;
		}
			break;
		case R.id.btn_left: {
			keyCode = KeyEvent.KEYCODE_DPAD_LEFT;
		}
			break;
		case R.id.btn_right: {
			keyCode = KeyEvent.KEYCODE_DPAD_RIGHT;
		}
			break;
		case R.id.btn_ok: {
			keyCode = KeyEvent.KEYCODE_ENTER;
		}
			break;
		case R.id.btn_power: {
			keyCode = KeyEvent.KEYCODE_POWER;
		}
			break;
		case R.id.btn_mute: {
			// keyCode = KeyEvent.KEYCODE_VOLUME_MUTE;
			keyCode = 164;
		}
			break;
		case R.id.btn_menu: {
			keyCode = KeyEvent.KEYCODE_MENU;
		}
			break;
		case R.id.btn_ch_up: {
			// keyCode = KeyEvent.KEYCODE_CHANNEL_UP;
			keyCode = 166;
		}
			break;
		case R.id.btn_ch_down: {
			// keyCode = KeyEvent.KEYCODE_CHANNEL_DOWN;
			keyCode = 167;
		}
			break;
		case R.id.btn_home: {
			keyCode = KeyEvent.KEYCODE_HOME;
		}
			break;
		case R.id.btn_back: {
			keyCode = KeyEvent.KEYCODE_BACK;
		}
			break;
		case R.id.btn_voice_up: {
			keyCode = KeyEvent.KEYCODE_VOLUME_UP;
		}
			break;
		case R.id.btn_voice_down: {
			keyCode = KeyEvent.KEYCODE_VOLUME_DOWN;
		}
			break;

		case R.id.btn_connect: {
			Intent mIntent = new Intent(this, NetServer.class);
			startService(mIntent);
			return;
		}
		case R.id.btn_finish: {
			this.finish();
			return;
		}
		}

		sendKey(keyCode);
	}

	public void sendKey(int keyCode) {
		if (mSocket == null) {
			Log.i(TAG, "mSocket==null");
			return;
		}
		if (mSocket.isClosed() || !mSocket.isConnected()) {
			Log.i(TAG, "mSocket is not connected");
			return;
		}

		if (thread == null) {
			Log.i(TAG, "thread is null");
			return;
		}

		// 暂停心跳包发送
		heard_flag = false;
		synchronized (mHeardThread) {
			mHeardThread.notify();
		}

		try {
			value[0] = (byte) 02;
			value[1] = (byte) 00;
			value[2] = (byte) 00;
			value[3] = (byte) 00;
			value[4] = (byte) keyCode;
			value[5] = (byte) 00;
			value[6] = (byte) 00;
			value[7] = (byte) 00;
			thread.out.write(value, 0, value.length);
			thread.out.flush();
			// Log.i(TAG, new String(value));
			sb.delete(0, sb.length());
			sb.append("send packet:");
			for (int i = 0; i < value.length; i++) {
				sb.append(value[i]);
				sb.append(":");
			}
			Message msg = Message.obtain(mHandler, NetTools.MSG_UP_TEXT,
					sb.toString());
			msg.sendToTarget();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		mHandler.postDelayed(new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				heard_flag = true;
				if (mHeardThread == null) {
					return;
				}
				synchronized (mHeardThread) {

					mHeardThread.notify();
				}
			}
		}, NetTools.BACKLOG * 1000);

		sb.delete(0, sb.length());
	}

	public void sendHeardPacket() {
		if (mSocket == null) {
			Message msg = Message.obtain(mHandler, NetTools.MSG_UP_TEXT,
					"mSocket is null");
			msg.sendToTarget();
			return;
		}
		if (mSocket.isClosed() || !mSocket.isConnected()) {
			Message msg = Message.obtain(mHandler, NetTools.MSG_UP_TEXT,
					"mSocket is not connect");
			msg.sendToTarget();
			return;
		}

		if (thread == null) {
			Message msg = Message.obtain(mHandler, NetTools.MSG_UP_TEXT,
					"thread is null");
			msg.sendToTarget();
			return;
		}

		try {
			thread.out.write(NetTools.KEEPALIVE, 0, NetTools.KEEPALIVE.length);
			thread.out.flush();
			Message msg = Message.obtain(mHandler, NetTools.MSG_UP_TEXT,
					"send heard packet");
			msg.sendToTarget();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		sb.delete(0, sb.length());

	}

	public void sendValue(byte[] value) {
		if (mSocket == null || mSocket.isClosed() || !mSocket.isConnected()) {
			Log.i(TAG, "mSocket is not connected");
			return;
		}

		if (thread == null) {
			Log.i(TAG, "thread is null");
			return;
		}

		try {
			thread.out.write(value, 0, value.length);
			thread.out.flush();
			Log.i(TAG, new String(value));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		sb.delete(0, sb.length());
	}

完整代码下载地: 请点击我

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ytmfdw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值