上一篇完成了在Android6.0以上的手机申请动态权限,采集实时的GPS数据并显示。我们项目需要的是将GPS数据(非视频数据)和视频数据传输到服务器,这里一般采用socket通信进行传输。
目录
- 服务器端(windows)
- 客户端(Android手机)
原本在java课上学过一些很简单的socket开发,但是在查阅资料的过程中,发现了这篇文章:Android:这是一份很详细的Socket使用攻略 使用了一个高并发的socket框架mina,也满足了我们项目需要的多个客户端连接服务器端的要求,安全性之类的也有保障,所以打算直尝试使用这个。
这是mina的一点介绍:Apache Mina(一)
1.服务器端(windows)
服务器端在eclipse平台运行,需要链接两个mina的jar包,网上可以搜到很多教程(其实是懒得找自己以前看的那个了)
1)首先在public类里声明端口8989等等信息
public class server {
public static void main(String[] args) {
NioSocketAcceptor acceptor = null;
try {
acceptor = new NioSocketAcceptor();
acceptor.setHandler(new TestHandler());
acceptor.getFilterChain().addLast("mFilter", new ProtocolCodecFilter(new TextLineCodecFactory()));
acceptor.setReuseAddress(true);
acceptor.bind(new InetSocketAddress(8989));
} catch (Exception e) {
e.printStackTrace();
}
}
}
2)实现handler类,进行数据的接收、发送、连接开连接关等等。messageReceived中注释的部分是要和服务器端的python程序通信建立的,不需要的话直接删去就可以。
从客户端接收的下次即message,System.out.println("recieve : " + (String) message);
这一行是将message转换为string类型打印出来。
class TestHandler extends IoHandlerAdapter {
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
System.out.println("exceptionCaught: " + cause);
}
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
// message为接收到的信息
System.out.println("recieve : " + (String) message);
// Socket socket = null;
// String codeAdress = "127.0.0.1";
// try {
// socket = new Socket(codeAdress,8990);
// OutputStream outputStream = socket.getOutputStream();
// InputStream inputStream = socket.getInputStream();
// byte[] bytes = new byte[1024];
// //发送数据
// outputStream.write(((String) message).getBytes());
// } catch (IOException e) {
// e.printStackTrace();
// }
}
@Override
public void messageSent(IoSession session, Object message) throws Exception {
//在这里可以向客户端发送消息
}
@Override
public void sessionClosed(IoSession session) throws Exception {
System.out.println("sessionClosed");
}
@Override
public void sessionOpened(IoSession session) throws Exception {
System.out.println("sessionOpen");
}
@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
}
}
2.客户端(Android手机)
1)定义变量。用到线程池,在建立连接和发送信息时用子线程进行。
//定位变量
private LocationManager lm;
private StringBuilder loca_data;
// Socket变量
private Socket socket;
// 线程池
// 为了方便展示,此处直接采用线程池进行线程管理,而没有一个个开线程
private ExecutorService mThreadPool;
long timeGetTime =new Date().getTime();
private Timer timer = new Timer(true);
// 输出流对象
OutputStream outputStream;
// 连接 断开连接 发送数据到服务器 的按钮变量
private Button btnConnect, btnDisconnect, btnSend1, btnSend2;
//显示GPS信息变量
private TextView tv_show;
//地址变量
private EditText urlpush;
2)给按钮connect注册事件:和服务器建立连接
/**
* 创建客户端 & 服务器的连接
*/
btnConnect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 利用线程池直接开启一个线程 & 执行该线程
mThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
// 创建Socket对象 & 指定服务端的IP 及 端口号
socket = new Socket(urlpush.getText().toString(), 8989);
// 判断客户端和服务器是否连接成功
System.out.println(socket.isConnected());
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
});
3)给按钮send1注册事件:发送GPS定位数据
其中line = loca_data;
即定位数据,采用定时器定时500ms发送
/**
* 发送消息 给 服务器
*/
btnSend1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 利用线程池直接开启一个线程 & 执行该线程
mThreadPool.execute(new Runnable() {
@Override
public void run() {
/**用定时器间隔发送*/
//定时执行任务
TimerTask task = new TimerTask() {
StringBuilder line;
@Override
public void run() {
try {
outputStream = socket.getOutputStream();
line = loca_data;
outputStream.write((line + "\n").getBytes("utf-8"));
//这里将缓冲区的数据冲入
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
};
timer.schedule(task, 1000, 500);
}
});
}
});
4)为了满足测试需求,定义了按钮send2:发送内置的已经采集好的GPS定位数据。
final InputStream inputStream = getResources().openRawResource(R.raw.n);
btnSend2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mThreadPool.execute(new Runnable() {
@Override
public void run() {
/**用定时器间隔发送*/
//定时执行任务
String line;
try {
outputStream = socket.getOutputStream();
InputStreamReader isr = new InputStreamReader(inputStream);
BufferedReader br = new BufferedReader(isr);
while ((line = br.readLine()) != null) {
Thread.sleep(50);//伪计时器
outputStream.write((line + "\n").getBytes("utf-8"));
//这里将缓冲区的数据冲入
outputStream.flush();
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
});
5)定义按钮disconnect:停止发送,断开连接
/**
* 断开客户端 & 服务器的连接
*/
btnDisconnect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
// 断开 客户端发送到服务器 的连接,即关闭输出流对象OutputStream
outputStream.close();
// 最终关闭整个Socket连接
socket.close();
// 判断客户端和服务器是否已经断开连接
System.out.println(socket.isConnected());
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
5)这里有点笨的用了这样的方法进行更新GPS数据
//定义一个更新显示的方法
private StringBuilder updateShow(Location location) {
if (location != null) {
StringBuilder sb = new StringBuilder();
sb.append("当前的位置信息:\n");
sb.append("经度:" + location.getLongitude() + "\n");
sb.append("纬度:" + location.getLatitude() + "\n");
sb.append("高度:" + location.getAltitude() + "\n");
sb.append("速度:" + location.getSpeed() + "\n");
sb.append("方向:" + location.getBearing() + "\n");
sb.append("定位精度:" + location.getAccuracy() + "\n");
sb.append("时间:" + timeGetTime + "\n");
tv_show.setText(sb.toString());
StringBuilder sb1 = new StringBuilder();
int id = 111;
sb1.append("{'id':'"+ id + "',");
sb1.append("'accuracy':'"+ location.getAccuracy() + "',");
sb1.append("'speed':'"+ location.getSpeed()+ "',");
sb1.append("'direction':'"+ location.getBearing() + "',");
sb1.append("'wgs84':["+ location.getLongitude() + "," + location.getLatitude() + "],");
sb1.append("'altitude':'"+ location.getAltitude() + "',");
sb1.append("'timestamp':'"+ timeGetTime + "'}");
return sb1;
} else {
tv_show.setText("");
return null;
}
}
两端搭建完毕后,将电脑连接手机的wifi热点,在app上方输入电脑ip地址
运行电脑的java程序,依次点击connect建立连接
点击send1进行GPS数据的发送
点击disconnect断开连接
至此完毕。
等我能进去github了再传源码