好久没写博客了,今天来写一篇之前实现过的,算是温故而知新吧。
先说下功能:在局域网内,手机来遥控智能电视,都是基于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());
}
完整代码下载地: 请点击我