最近做项目,用到了socket通讯,这里先使用的是tcp/ip的方式来进行通讯的,至于socket 套接字和tcp的三次握手之类的东西,自己到网上找一下就有,这里只是介绍一下在Android中如何使用tcp方式进行通讯。
这里只是实现了较简单的功能,并没涉及到复杂的东西。
1、和后台进行socket连接。需要的是后台的ip地址和端口
和后台进行连接2、设置心跳包,发送命令或字节数组类似
通过线程池来管理心跳包发送和断线重连3、发送文件
发送assets下的文件,也可以是内存卡下的文件4、接收后台发送的消息
接收后台消息整体的代码,这里我为了检测连接的时间和发送文件需要的时间,使用了objectBox的数据库,进行了时间本地存储(addNote),不需要的直接去掉。
public class DealSocketServiceextends Service {
private StringTAG ="sun";
public DealSocketService() {}
@Override
public IBinder onBind(Intent intent) {
return new ClientBinder();
}
public class ClientBinderextends Binder {
private BoxnotesBox;//数据库相关
private int mHeart_spacetime =5 *1000;//心跳间隔时间
private BufferedInputStreambis;
private BufferedOutputStreambos;
private ReadThreadmReadThread;
private HandlermHandler =new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 66:
MyApp.flag =true;
Toast.makeText(getApplication(),"连接成功", Toast.LENGTH_SHORT).show();
break;
}
}
};
private SocketmSocket;
private ExecutorServicemExecutorService;
private int tryCount =0;//重试次数
public void startConnect() {
notesBox = ObjectBox.get().boxFor(Note.class);
//在子线程进行网络操作
// Service也是运行在主线程,千万不要以为Service意思跟后台运行很像,就以为Service运行在后台子线程
if (mExecutorService ==null) {
mExecutorService = Executors.newCachedThreadPool();
}
mExecutorService.execute(connectRunnable);
}
private RunnableconnectRunnable =new Runnable() {
@Override
public void run() {
try {
// 建立Socket连接 tryCount == 0 是刚进程序进行连接 == 1 是断线后进行重连的操作
if(tryCount ==1||tryCount ==0){
addNote("开始连接后台");
}
mSocket =new Socket();
mSocket.connect(new InetSocketAddress("192.168.56.1",11001),10);
bis =new BufferedInputStream(mSocket.getInputStream());
bos =new BufferedOutputStream(mSocket.getOutputStream());
// 创建读取服务器心跳的线程
mReadThread =new ReadThread();
mReadThread.start();
//开启心跳,每隔15秒钟发送一次心跳
mHandler.post(mHeartRunnable);
tryCount =1;
addNote("后台连接成功");
mHandler.sendEmptyMessage(66);
}catch (Exception e) {
MyApp.flag =false;
tryCount++;
e.printStackTrace();
Log.i(TAG,"Socket连接建立失败,正在尝试第" +tryCount +"次重连");
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mExecutorService.execute(connectRunnable);
}
},mHeart_spacetime);
}
}
};
public class ReadThreadextends Thread {
@Override
public void run() {
int size;
byte[] buffer =new byte[1024];
try {
while ((size =bis.read(buffer)) != -1) {
//这里是接收的字符串消息,如果是文件,直接指定文件地址,通过写出流进行保存即可
String str =new String(buffer,0, size);
addNote("接收到后台消息=="+ str);
Log.i(TAG,"我收到来自服务器的消息: " + str);
//收到消息后,先移除掉之前的断连消息,然后冲设置一个指定时间后执行的断连任务。实际使用中,后台收到心跳包后,会进行回复,如果收到回复,说明连接活着,
// 反之说明连接已经挂掉,需要重连。由于在发送心跳的地方已经做了重连,这里就不再进行设置重连
mHandler.removeCallbacks(disConnectRunnable);
mHandler.postDelayed(disConnectRunnable,mHeart_spacetime *4);
}
}catch (Exception e) {
e.printStackTrace();
MyApp.flag =false;
}
}
}
private RunnablemHeartRunnable =new Runnable() {
@Override
public void run() {
sendHeart();
}
};
/**
* 这是发送心跳包的方法,单独放到一个线程中去
*/
private void sendHeart() {
mExecutorService.execute(new Runnable() {
@Override
public void run() {
try {
bos.write("00".getBytes());
//一定不能忘记这步操作
bos.flush();
//发送成功以后,重新建立一个心跳消息
mHandler.postDelayed(mHeartRunnable,mHeart_spacetime);
Log.i(TAG,"我发送给服务器的消息: 心跳包消息");
}catch (Exception e) {
e.printStackTrace();
MyApp.flag =false;
Log.i(TAG,"心跳任务发送失败,正在尝试第" +tryCount +"次重连");
mExecutorService.execute(connectRunnable);
}
}
});
}
public void sendData(String content) {
mExecutorService.execute(new Runnable() {
@Override
public void run() {
try {
//在发送数据前,先将之前的心跳包停掉
addNote("向后台发送消息");
mHandler.removeCallbacks(mHeartRunnable);
bos.write(content.getBytes());
//一定不能忘记这步操作
bos.flush();
addNote("向后台发送消息成功");
//发送成功以后,重新建立一个心跳消息
mHandler.postDelayed(mHeartRunnable,mHeart_spacetime);
Log.i(TAG,"我发送给服务器的消息: 字符串消息");
}catch (Exception e) {
e.printStackTrace();
MyApp.flag =false;
Log.i(TAG,"数据任务发送失败,正在尝试第" +tryCount +"次重连");
//mExecutorService.schedule(connectRunnable,mHeart_spacetime, TimeUnit.SECONDS);
mExecutorService.execute(connectRunnable);
}
}
});
}
public void sendFile(String path) {
mExecutorService.execute(new Runnable() {
@Override
public void run() {
try {
addNote("向后台发送文件");
mHandler.removeCallbacks(mHeartRunnable);
OutputStream ss =mSocket.getOutputStream();
InputStream in = getAssets().open("meet.docx");
//FileInputStream ii = new FileInputStream(new File(path));
int size = -1;
byte[] car =new byte[1024];
while ((size = in.read(car,0,1024)) != -1) {
ss.write(car,0, size);
}
//一定不能忘记这步操作
ss.flush();
in.close();
//发送成功以后,重新建立一个心跳消息
addNote("向后台发送文件成功");
mHandler.postDelayed(mHeartRunnable,mHeart_spacetime);
Log.i(TAG,"我发送给服务器的消息: 文件消息");
}catch (Exception e) {
e.printStackTrace();
MyApp.flag =false;
Log.i(TAG,"文件任务发送失败,正在尝试第" +tryCount +"次重连");
//mExecutorService.schedule(connectRunnable,mHeart_spacetime, TimeUnit.SECONDS);
mExecutorService.execute(connectRunnable);
}
}
});
}
private RunnabledisConnectRunnable =new Runnable() {
@Override
public void run() {
disConnect();
}
};
private void disConnect() {
mExecutorService.execute(new Runnable() {
@Override
public void run() {
try {
Log.i(TAG,"正在执行断连: disConnect");
//执行Socket断连
mHandler.removeCallbacks(mHeartRunnable);
if (mReadThread !=null) {
mReadThread.interrupt();
}
if (bos !=null) {
bos.close();
}
if (bis !=null) {
bis.close();
}
if (mSocket !=null) {
mSocket.shutdownInput();
mSocket.shutdownOutput();
mSocket.close();
}
MyApp.flag =false;
}catch (Exception e) {
e.printStackTrace();
}
}
});
}
public void destory() {
disConnect();
notesBox.removeAll();
mHandler.removeCallbacksAndMessages(null);
}
private void addNote(String ss) {
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
String comment ="添加时间: " + df.format(new Date());
Note note =new Note();
note.setText(ss);
note.setComment(comment);
note.setDate(new Date());
notesBox.put(note);
}
}
}
网友评论