需求:
1.一个android端的service后台运行的程序,作为socket的服务器端;用于接收Pc client端发来的命令,来处理数据后,把结果发给PC client
2.PC端程序,作为socket的客户端,用于给android手机端发操作命令
难点分析:
1.手机一定要有adb模式,即插上USB线时马上提示的对话框选adb。好多对手机的操作都可以用adb直接作。
不过,我发现LG GW880就没有,要去下载个
2.android默认手机端的IP为“127.0.0.1”
3.要想联通PC与android手机的sokcet,一定要用adb forward 来作下端口转发才能连上socket.
- Runtime.getRuntime().exec("adbforwardtcp:12580tcp:10086");
- Thread.sleep(3000);
4.android端的service程序Install到手机上容易,但是还要有方法来从PC的client端来启动手机上的service ,这个办法可以通过PC端adb命令来发一个Broastcast,手机端再写个接收BroastcastReceive来接收这个Broastcast,在这个BroastcastReceive来启动service
pc端命令:
- Runtime.getRuntime().exec(
- "adbshellambroadcast-aNotifyServiceStart");
android端的代码:ServiceBroadcastReceiver.java
- packagecom.otheri.service;
- importandroid.content.BroadcastReceiver;
- importandroid.content.Context;
- importandroid.content.Intent;
- importandroid.util.Log;
- publicclassServiceBroadcastReceiverextendsBroadcastReceiver{
- privatestaticStringSTART_ACTION="NotifyServiceStart";
- privatestaticStringSTOP_ACTION="NotifyServiceStop";
- @Override
- publicvoidonReceive(Contextcontext,Intentintent){
- Log.d(androidService.TAG,Thread.currentThread().getName()+"---->"
- +"ServiceBroadcastReceiveronReceive");
- Stringaction=intent.getAction();
- if(START_ACTION.equalsIgnoreCase(action)){
- context.startService(newIntent(context,androidService.class));
- Log.d(androidService.TAG,Thread.currentThread().getName()+"---->"
- +"ServiceBroadcastReceiveronReceivestartend");
- }elseif(STOP_ACTION.equalsIgnoreCase(action)){
- context.stopService(newIntent(context,androidService.class));
- Log.d(androidService.TAG,Thread.currentThread().getName()+"---->"
- +"ServiceBroadcastReceiveronReceivestopend");
- }
- }
- }
5.由于是USB连接,所以socket就可以设计为一但连接就一直联通,即在new socket和开完out,in流后,就用个while(true){}来循环PC端和android端的读和写
android的代码:
- publicvoidrun(){
- Log.d(androidService.TAG,Thread.currentThread().getName()+"---->"
- +"aclienthasconnectedtoserver!");
- BufferedOutputStreamout;
- BufferedInputStreamin;
- try{
- StringcurrCMD="";
- out=newBufferedOutputStream(client.getOutputStream());
- in=newBufferedInputStream(client.getInputStream());
- androidService.ioThreadFlag=true;
- while(androidService.ioThreadFlag){
- try{
- if(!client.isConnected()){
- break;
- }
- Log.v(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"willread......");
- currCMD=readCMDFromSocket(in);
- Log.v(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"**currCMD===="+currCMD);
- if(currCMD.equals("1")){
- out.write("OK".getBytes());
- out.flush();
- }elseif(currCMD.equals("2")){
- out.write("OK".getBytes());
- out.flush();
- }elseif(currCMD.equals("3")){
- out.write("OK".getBytes());
- out.flush();
- }elseif(currCMD.equals("4")){
- try{
- out.write("servicereceiveOK".getBytes());
- out.flush();
- }catch(IOExceptione){
- e.printStackTrace();
- }
- byte[]filelength=newbyte[4];
- byte[]fileformat=newbyte[4];
- byte[]filebytes=null;
- filebytes=receiveFileFromSocket(in,out,filelength,
- fileformat);
- try{
- Filefile=FileHelper.newFile("R0013340.JPG");
- FileHelper.writeFile(file,filebytes,0,
- filebytes.length);
- }catch(IOExceptione){
- e.printStackTrace();
- }
- }elseif(currCMD.equals("exit")){
- }
- }catch(Exceptione){
- Log.e(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"readwriteerror111111");
- }
- }
- out.close();
- in.close();
- }catch(Exceptione){
- Log.e(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"readwriteerror222222");
- e.printStackTrace();
- }finally{
- try{
- if(client!=null){
- Log.v(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"client.close()");
- client.close();
- }
- }catch(IOExceptione){
- Log.e(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"readwriteerror333333");
- e.printStackTrace();
- }
- }
6.如果是在PC端和android端的读写操作来while(true){}循环,这样socket流的结尾不好判断,不能用“-1”来判断,因为“-1”是只有在socket关闭时才作为判断结尾。
7.socket在out.write(bytes);时,要是数据太大时,超过socket的缓存,socket自动分包发送,所以对方就一定要用循环来多次读。最好的办法就是服务器和客户端协议好,比如发文件时,先写过来一个要发送的文件的大小,然后再发送文件;对方用这个大小,来循环读取数据。
android端接收数据的代码:
- publicstaticbyte[]receiveFileFromSocket(InputStreamin,
- OutputStreamout,byte[]filelength,byte[]fileformat){
- byte[]filebytes=null;
- try{
- intfilelen=MyUtil.bytesToInt(filelength);
- Stringstrtmp="readfilelengthok:"+filelen;
- out.write(strtmp.getBytes("utf-8"));
- out.flush();
- filebytes=newbyte[filelen];
- intpos=0;
- intrcvLen=0;
- while((rcvLen=in.read(filebytes,pos,filelen-pos))>0){
- pos+=rcvLen;
- }
- Log.v(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"readfileOK:filesize="+filebytes.length);
- out.write("readfileok".getBytes("utf-8"));
- out.flush();
- }catch(Exceptione){
- Log.v(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"receiveFileFromSocketerror");
- e.printStackTrace();
- }
- returnfilebytes;
- }
8.socket的最重要的机制就是读写采用的是阻塞的方式,如果客户端作为命令发起者,服务器端作为接收者的话,只有当客户端client用out.writer()写到输出流里后,即流中有数据service的read才会执行,不然就会一直停在read()那里等数据。
9.还要让服务器端可以同时连接多个client,即服务器端用new thread()来作数据读取操作。
源码:
客户端(pc端):
testPcClient.java
android服务器端:
主类androidService.java
- packagecom.otheri.service;
- importjava.io.File;
- importjava.io.IOException;
- importjava.net.ServerSocket;
- importjava.net.Socket;
- importandroid.app.Service;
- importandroid.content.BroadcastReceiver;
- importandroid.content.Context;
- importandroid.content.Intent;
- importandroid.content.IntentFilter;
- importandroid.os.IBinder;
- importandroid.util.Log;
- publicclassandroidServiceextendsService{
- publicstaticfinalStringTAG="TAG";
- publicstaticBooleanmainThreadFlag=true;
- publicstaticBooleanioThreadFlag=true;
- ServerSocketserverSocket=null;
- finalintSERVER_PORT=10086;
- FiletestFile;
- privatesysBroadcastReceiversysBR;
- @Override
- publicvoidonCreate(){
- super.onCreate();
- Log.v(TAG,Thread.currentThread().getName()+"---->"+"onCreate");
- sysRegisterReceiver();
- newThread(){
- publicvoidrun(){
- doListen();
- };
- }.start();
- }
- privatevoiddoListen(){
- Log.d(TAG,Thread.currentThread().getName()+"---->"
- +"doListen()START");
- serverSocket=null;
- try{
- Log.d(TAG,Thread.currentThread().getName()+"---->"
- +"doListen()newserverSocket");
- serverSocket=newServerSocket(SERVER_PORT);
- booleanmainThreadFlag=true;
- while(mainThreadFlag){
- Log.d(TAG,Thread.currentThread().getName()+"---->"
- +"doListen()listen");
- Socketclient=serverSocket.accept();
- newThread(newThreadReadWriterIOSocket(this,client)).start();
- }
- }catch(IOExceptione1){
- Log.v(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"newserverSocketerror");
- e1.printStackTrace();
- }
- }
- privatevoidsysRegisterReceiver(){
- Log.v(TAG,Thread.currentThread().getName()+"---->"
- +"sysRegisterReceiver");
- sysBR=newsysBroadcastReceiver();
- IntentFilterfilter1=newIntentFilter();
- filter1.addAction("android.intent.action.PACKAGE_ADDED");
- filter1.addDataScheme("package");
- filter1.addAction("android.intent.action.PACKAGE_REMOVED");
- filter1.addDataScheme("package");
- registerReceiver(sysBR,filter1);
- }
- privateclasssysBroadcastReceiverextendsBroadcastReceiver{
- @Override
- publicvoidonReceive(Contextcontext,Intentintent){
- Stringaction=intent.getAction();
- if(action.equalsIgnoreCase("android.intent.action.PACKAGE_ADDED")){
- }elseif(action
- .equalsIgnoreCase("android.intent.action.PACKAGE_REMOVED")){
- }
- Log.v(TAG,Thread.currentThread().getName()+"---->"
- +"sysBroadcastReceiveronReceive");
- }
- }
- @Override
- publicvoidonDestroy(){
- super.onDestroy();
- mainThreadFlag=false;
- ioThreadFlag=false;
- try{
- Log.v(TAG,Thread.currentThread().getName()+"---->"
- +"serverSocket.close()");
- serverSocket.close();
- }catch(IOExceptione){
- e.printStackTrace();
- }
- Log.v(TAG,Thread.currentThread().getName()+"---->"
- +"****************onDestroy****************");
- }
- @Override
- publicvoidonStart(Intentintent,intstartId){
- Log.d(TAG,Thread.currentThread().getName()+"---->"+"onStart()");
- super.onStart(intent,startId);
- }
- @Override
- publicIBinderonBind(Intentarg0){
- Log.d(TAG,"onBind");
- returnnull;
- }
- }
用于接收PC发来的Broastcast并启动主类service的ServiceBroadcastReceiver.java
- packagecom.otheri.service;
- importandroid.content.BroadcastReceiver;
- importandroid.content.Context;
- importandroid.content.Intent;
- importandroid.util.Log;
- publicclassServiceBroadcastReceiverextendsBroadcastReceiver{
- privatestaticStringSTART_ACTION="NotifyServiceStart";
- privatestaticStringSTOP_ACTION="NotifyServiceStop";
- @Override
- publicvoidonReceive(Contextcontext,Intentintent){
- Log.d(androidService.TAG,Thread.currentThread().getName()+"---->"
- +"ServiceBroadcastReceiveronReceive");
- Stringaction=intent.getAction();
- if(START_ACTION.equalsIgnoreCase(action)){
- context.startService(newIntent(context,androidService.class));
- Log.d(androidService.TAG,Thread.currentThread().getName()+"---->"
- +"ServiceBroadcastReceiveronReceivestartend");
- }elseif(STOP_ACTION.equalsIgnoreCase(action)){
- context.stopService(newIntent(context,androidService.class));
- Log.d(androidService.TAG,Thread.currentThread().getName()+"---->"
- +"ServiceBroadcastReceiveronReceivestopend");
- }
- }
- }
用于新socket连接的读写线程类ThreadReadWriterIOSocket.java
- packagecom.otheri.service;
- importjava.io.BufferedInputStream;
- importjava.io.BufferedOutputStream;
- importjava.io.ByteArrayOutputStream;
- importjava.io.File;
- importjava.io.IOException;
- importjava.io.InputStream;
- importjava.io.OutputStream;
- importjava.net.Socket;
- importandroid.content.Context;
- importandroid.util.Log;
- importcom.otheri.util.FileHelper;
- importcom.otheri.util.MyUtil;
- publicclassThreadReadWriterIOSocketimplementsRunnable{
- privateSocketclient;
- privateContextcontext;
- ThreadReadWriterIOSocket(Contextcontext,Socketclient){
- this.client=client;
- this.context=context;
- }
- @Override
- publicvoidrun(){
- Log.d(androidService.TAG,Thread.currentThread().getName()+"---->"
- +"aclienthasconnectedtoserver!");
- BufferedOutputStreamout;
- BufferedInputStreamin;
- try{
- StringcurrCMD="";
- out=newBufferedOutputStream(client.getOutputStream());
- in=newBufferedInputStream(client.getInputStream());
- androidService.ioThreadFlag=true;
- while(androidService.ioThreadFlag){
- try{
- if(!client.isConnected()){
- break;
- }
- Log.v(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"willread......");
- currCMD=readCMDFromSocket(in);
- Log.v(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"**currCMD===="+currCMD);
- if(currCMD.equals("1")){
- out.write("OK".getBytes());
- out.flush();
- }elseif(currCMD.equals("2")){
- out.write("OK".getBytes());
- out.flush();
- }elseif(currCMD.equals("3")){
- out.write("OK".getBytes());
- out.flush();
- }elseif(currCMD.equals("4")){
- try{
- out.write("servicereceiveOK".getBytes());
- out.flush();
- }catch(IOExceptione){
- e.printStackTrace();
- }
- byte[]filelength=newbyte[4];
- byte[]fileformat=newbyte[4];
- byte[]filebytes=null;
- filebytes=receiveFileFromSocket(in,out,filelength,
- fileformat);
- try{
- Filefile=FileHelper.newFile("R0013340.JPG");
- FileHelper.writeFile(file,filebytes,0,
- filebytes.length);
- }catch(IOExceptione){
- e.printStackTrace();
- }
- }elseif(currCMD.equals("exit")){
- }
- }catch(Exceptione){
- Log.e(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"readwriteerror111111");
- }
- }
- out.close();
- in.close();
- }catch(Exceptione){
- Log.e(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"readwriteerror222222");
- e.printStackTrace();
- }finally{
- try{
- if(client!=null){
- Log.v(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"client.close()");
- client.close();
- }
- }catch(IOExceptione){
- Log.e(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"readwriteerror333333");
- e.printStackTrace();
- }
- }
- }
- publicstaticbyte[]receiveFileFromSocket(InputStreamin,
- OutputStreamout,byte[]filelength,byte[]fileformat){
- byte[]filebytes=null;
- try{
- in.read(filelength);
- intfilelen=MyUtil.bytesToInt(filelength);
- Stringstrtmp="readfilelengthok:"+filelen;
- out.write(strtmp.getBytes("utf-8"));
- out.flush();
- filebytes=newbyte[filelen];
- intpos=0;
- intrcvLen=0;
- while((rcvLen=in.read(filebytes,pos,filelen-pos))>0){
- pos+=rcvLen;
- }
- Log.v(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"readfileOK:filesize="+filebytes.length);
- out.write("readfileok".getBytes("utf-8"));
- out.flush();
- }catch(Exceptione){
- Log.v(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"receiveFileFromSocketerror");
- e.printStackTrace();
- }
- returnfilebytes;
- }
- publicstaticStringreadCMDFromSocket(InputStreamin){
- intMAX_BUFFER_BYTES=2048;
- Stringmsg="";
- byte[]tempbuffer=newbyte[MAX_BUFFER_BYTES];
- try{
- intnumReadedBytes=in.read(tempbuffer,0,tempbuffer.length);
- msg=newString(tempbuffer,0,numReadedBytes,"utf-8");
- tempbuffer=null;
- }catch(Exceptione){
- Log.v(androidService.TAG,Thread.currentThread().getName()
- +"---->"+"readFromSocketerror");
- e.printStackTrace();
- }
- returnmsg;
- }
- }
后面是两个辅助类:
- packagecom.otheri.util;
- importjava.io.BufferedInputStream;
- importjava.io.File;
- importjava.io.FileInputStream;
- importjava.io.FileOutputStream;
- importjava.io.IOException;
- importcom.otheri.service.androidService;
- importandroid.util.Log;
- publicclassFileHelper{
- privatestaticStringFILEPATH="/sdcard";
- publicstaticFilenewFile(StringfileName){
- Filefile=null;
- try{
- file=newFile(FILEPATH,fileName);
- file.delete();
- file.createNewFile();
- }catch(IOExceptione){
- e.printStackTrace();
- }
- returnfile;
- }
- publicstaticvoidwriteFile(Filefile,byte[]data,intoffset,intcount)
- throwsIOException{
- FileOutputStreamfos=newFileOutputStream(file,true);
- fos.write(data,offset,count);
- fos.flush();
- fos.close();
- }
- publicstaticbyte[]readFile(StringfileName)throwsIOException{
- Filefile=newFile(FILEPATH,fileName);
- file.createNewFile();
- FileInputStreamfis=newFileInputStream(file);
- BufferedInputStreambis=newBufferedInputStream(fis);
- intleng=bis.available();
- Log.v(androidService.TAG,"filesize="+leng);
- byte[]b=newbyte[leng];
- bis.read(b,0,leng);
- bis.close();
- returnb;
- }
- }
- packagecom.otheri.util;
- importjava.io.InputStream;
- importandroid.util.Log;
- importcom.otheri.service.androidService;
- publicclassMyUtil{
- publicstaticintbytesToInt(byte[]bytes){
- intaddr=bytes[0]&0xFF;
- addr|=((bytes[1]<<8)&0xFF00);
- addr|=((bytes[2]<<16)&0xFF0000);
- addr|=((bytes[3]<<24)&0xFF000000);
- returnaddr;
- }
- publicstaticbyte[]intToByte(inti){
- byte[]abyte0=newbyte[4];
- abyte0[0]=(byte)(0xff&i);
- abyte0[1]=(byte)((0xff00&i)>>8);
- abyte0[2]=(byte)((0xff0000&i)>>16);
- abyte0[3]=(byte)((0xff000000&i)>>24);
- returnabyte0;
- }
- }