Android之Socket,Service通讯

来源:互联网 发布:windows fix it 下载 编辑:程序博客网 时间:2024/05/21 12:43

                           Android与服务器之间的通讯方式主要有两种。一种是Http通讯 , 一种是Socket通讯。两者最大的差异在于,Http连接使用的是“请求---响应方式”,即在请求是建立连接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据。而Socket则是在双方建立连接后就直接进行数据传输,在连接时可实现信息的主动推送,而不需要每次由客户端向服务端发送请求。 

                 

                 什么是Socket?又称套接字,是一种抽象层。在程序内部提供了与外界通讯的端口,即端口信息。通过建立Socket连接,可为通讯双方的传输提供通道。Socket的主要特点有数据丢失率低,使用简单且易于移植。

                   

                   本案例是基于TCP协议的Socket。服务端首先声明一个ServerSocket对象并且指定端口号。然后调用ServerSocket的accept()方法接收客户端的数据。accept()方法在没有数据进行接收的处于堵塞状态。(Socketsocket=serversocket.accept()),一旦接收到数据,通过inputstream读取接收的数据。


                     客户端创建一个Socket对象,指定服务器端的ip地址和端口号(Socketsocket=newSocket("172.168.10.108",8080);),通过inputstream读取数据,获取服务器发出的数据(OutputStreamoutputstream=socket.getOutputStream()),最后将要发送的数据写入到outputstream即可进行TCP协议的socket数据传输。

             项目结构:

                     

                      2. IMService.class                         

public class IMService extends Service {static Communication communication;public static String messageTag="com.gys.im.CYEJIMActivity";public static Notification notification;public static int messageId = 10000;private NotificationManager mNM;boolean isconnected;Timer timer=new Timer();@Overridepublic void onCreate() {// TODO Auto-generated method stub        communication=Communication.newInstance();        communication.setReceiver(this);        mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);        notification=new Notification(R.drawable.ic_launcher, "", System.currentTimeMillis());        notification.number=1;        timer.schedule(timerTask, 1000, 2000);}    public Handler handler= new Handler()    {    public void handleMessage(Message msg) {    String message=msg.obj.toString();    if(message.equals("start\n"))    {    start_check_in();    }else    {    Intent intent = new Intent(messageTag);    intent.putExtra("message", message);    IMService.this.sendBroadcast(intent);    }    }    };        public TimerTask timerTask=new TimerTask()    {@Overridepublic void run() {// TODO Auto-generated method stubisconnected=checkNetwork();if(!isconnected){showNotification("","");}}        };        /**     * 添加内容到发送消息队列     * @param str     */    public static void addPacket(String str)    {    communication.addPacket(str);    }        public static void wakeUp()    {    communication.wakeUp();    }        /**     * 开始发送心跳     */    protected void start_check_in()    {    communication.start_check_in();    }    public  boolean checkNetwork() {boolean flag = false;ConnectivityManager cwjManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);if (cwjManager.getActiveNetworkInfo() != null){flag = cwjManager.getActiveNetworkInfo().isAvailable();}return flag;}    private void showNotification(String statusInfo,String messageContent) {        PendingIntent contentIntent = PendingIntent.getActivity(this,0,null,0);                notification.when=System.currentTimeMillis();        notification.tickerText=statusInfo;            notification.setLatestEventInfo(this,"test",messageContent, null);            notification.contentIntent=contentIntent;            notification.vibrate = new long[] {100, 250, 100, 500};            messageNotificationAdd(messageId, notification);    }        /*add a nonotification*/    public void messageNotificationAdd(int notificationNo,Notification notification){    try    {    mNM.notify(notificationNo,notification);    }catch(Exception e)    {    e.printStackTrace();    }    notification.number++;//number 增加后,可以与以前的notification区分开来    }@Overridepublic void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();mNM.cancel(messageId);}@Overridepublic void onLowMemory() {// TODO Auto-generated method stubsuper.onLowMemory();}@Overridepublic void onStart(Intent intent, int startId) {// TODO Auto-generated method stubsuper.onStart(intent, startId);}@Overridepublic boolean onUnbind(Intent intent) {// TODO Auto-generated method stubreturn super.onUnbind(intent);}@Overridepublic IBinder onBind(Intent arg0) {// TODO Auto-generated method stubreturn null;}}

                3.Communication.class :

public class Communication {private NetTransportWorker transportWorker;private MessageWorker messageWorker;private static Communication instance;private Communication() {transportWorker = new NetTransportWorker();transportWorker.start();messageWorker = new MessageWorker(transportWorker);messageWorker.start();}public static Communication newInstance() {if (instance == null)instance = new Communication();return instance;}public NetTransportWorker getTransportWorker() {return transportWorker;}public MessageWorker getMessageWorker() {return messageWorker;}public void setReceiver(IMService service){transportWorker.setRecever(service);}//public void addReceiveInfoListener(ReceiveInfoListener listener) {//transportWorker.addReceiveInfoListener(listener);//}////public void removeReceiveInfoListener(ReceiveInfoListener listener) {//transportWorker.removeReceiveInfoListener(listener);//}public void reconnect() {transportWorker.notify();}private boolean sendDataToServer(String packet) {try {if (transportWorker.writeBuf(packet.getBytes("UTF8")))return true;} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return false;}/** 如果从不活动界面切换到聊天界面,此方法返回所有队列里面的信息数据包 **/public Queue<String> getReceivePackets() {return transportWorker.receiveQueue;}public void addPacket(String packet) {messageWorker.addPacket(packet);}public void wakeUp() {messageWorker.wakeUp();}public void start_check_in() {messageWorker.start_check_in();}public String newSessionID() {return String.valueOf(System.currentTimeMillis());}}
                   

                    4.MessageWorker.class: 

public class MessageWorker extends Thread {protected NetTransportWorker worker;protected Queue<String> sendQueue;protected Timer timer;protected TimerTask task;// 10S发送一个确认在线的报到protected final long delay = 30000;protected MessageWorker(final NetTransportWorker worker) {this.worker = worker;sendQueue = new ConcurrentLinkedQueue<String>();task = new TimerTask() {@Overridepublic void run() {// TODO Auto-generated method stubString packet = "hello\n";addPacket(packet);wakeUp();}};}public static String getLocalHostIp()   {    String ipaddress = "no_data";    try    {        Enumeration<NetworkInterface> en = NetworkInterface                .getNetworkInterfaces();        // 遍历所用的网络接口        while (en.hasMoreElements())        {            NetworkInterface nif = en.nextElement();// 得到每一个网络接口绑定的所有ip            Enumeration<InetAddress> inet = nif.getInetAddresses();            // 遍历每一个接口绑定的所有ip            while (inet.hasMoreElements())            {                InetAddress ip = inet.nextElement();                if (!ip.isLoopbackAddress()                        && InetAddressUtils.isIPv4Address(ip                                .getHostAddress()))                {                    return ipaddress =ip.getHostAddress();                }            }        }    }    catch (SocketException e)    {        System.out.print("获取IP 失败"+e.toString());        e.printStackTrace();    }    return ipaddress;}protected void start_check_in() {if(timer==null){timer=new Timer();timer.schedule(task, delay, delay);}}public void addPacket(String packet) {sendQueue.add(packet);wakeUp();}public synchronized void wakeUp() {notify();}@Overridepublic synchronized void run() {// TODO Auto-generated method stubwhile (true) {try {while (sendQueue.size() > 0) {String packet = sendQueue.peek();if (worker.writeBuf(packet.getBytes("UTF8"))){sendQueue.poll();}else{sendQueue.clear();}}wait();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}


                     5.NetTransportWorker.class:

public class NetTransportWorker extends Thread {protected Socket socket = null;protected static final int CONNECT_TIMEOUT = 10000;protected static final int READ_TIMEOUT = 60000;protected static final int RECONNECT_TIME = 30000;protected ByteArrayOutputStream readByte;protected DataOutputStream readData;static {java.lang.System.setProperty("java.net.preferIPv6Addresses", "true");};protected final byte connect = 1;protected final byte running = 2;protected byte state = connect;protected boolean onWork;// 是否工作状态public static final String sysError = "与服务器连接断开了,马上重新连接!";protected IMService service;protected Queue<String> receiveQueue;        String packet;DataOutputStream output;DataInputStream input;protected NetTransportWorker() {onWork = true;readByte = new ByteArrayOutputStream();readData = new DataOutputStream(readByte);receiveQueue = new ConcurrentLinkedQueue<String>();}protected void setRecever(IMService service){this.service=service;}@Overridepublic void run() {// TODO Auto-generated method stubwhile (onWork) {switch (state) {case connect:connect();break;case running:running();break;}}}private synchronized void running() {try {    byte[] buffer=new byte[1024];    ByteArrayOutputStream baos=new ByteArrayOutputStream();    byte[] reallyByte; int number; while((number=input.read(buffer, 0, buffer.length))>0) {            baos.write(buffer, 0, number);    reallyByte=baos.toByteArray();    String info=new String(reallyByte);Message mess=new Message();mess.obj=info;service.handler.sendMessage(mess);baos.reset(); }} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();sendInfoMessageToUI(sysError);close();}}//protected  void handleTimeout(Selector selector) {//  try{//   Iterator<SelectionKey> iter = selector.keys().iterator();//   while(iter.hasNext()){//    SelectionKey key = iter.next();//    System.out.println("clear:"+key);//    //            if ( (key.interestOps() & SelectionKey.OP_READ) !=0 ) {//             key.cancel();//             key.attach(null);//             key.channel().close();//            }//   }//  }catch(Exception e2){//   e2.printStackTrace();//  }//    } //public final String readBuf(InputStream input)//throws IOException {//    byte[] buffer=new byte[1024];//    ByteArrayOutputStream baos=new ByteArrayOutputStream();// int number;// while((number=input.read(buffer, 0, buffer.length))>0)// {// baos.write(buffer, 0, number); // }//byte[] reallyByte=baos.toByteArray();//String info=new String(reallyByte);//return info;//}protected final boolean writeBuf(byte[] data) throws IOException {if (socket != null && socket.isConnected()&&output!=null&&!socket.isOutputShutdown()&& state == running) {output.write(data);output.flush();return true;} else if (state != running) {return false;}return false;}private void sendInfoMessageToUI(String text) {//TuliaoBaseActivity.sendMessage(ProtocolConst.CMD_SYSTEM_ERROR, text);////self.setOnline(false);//Iterator<Integer> keys = all_user.keySet().iterator();//while (keys.hasNext()) {//UserInfo info = all_user.get(keys.next());//info.setOnline(false);//}//Message msg = new Message();//msg.what = ProtocolConst.CMD_HAS_USER_OFFLINE;//msg.obj = all_user;//TuliaoBaseActivity.sendMessage(msg);}/** * 唤起连接线程重新连接 */protected synchronized void reconnect() {close();//notify();}private synchronized void connect() {try {SocketAddress sa=new InetSocketAddress(ProtocolConst.ip,ProtocolConst.port);socket=new Socket();socket.setSoTimeout(READ_TIMEOUT);socket.setTcpNoDelay(true);//socket.setTrafficClass(0x04 | 0x10);socket.connect(sa, CONNECT_TIMEOUT);output=new DataOutputStream(socket.getOutputStream());input=new DataInputStream(socket.getInputStream());if (socket.isConnected()) {// 连接成功开始监听服务端消息// 发送一个验证数据包到服务器进行验证state = running;writeBuf("start\n".getBytes("UTF8"));            //客户端接收到start表示心跳的开始} else {// 关闭通道过30S重新开始连接sendInfoMessageToUI("服务器连接失败" + (RECONNECT_TIME / 1000)+ "秒后再尝试连接");wait(RECONNECT_TIME);reconnect();}} catch (Exception e) {// TODO Auto-generated catch block// 有异常关闭通道过60S重新开始连接e.printStackTrace();sendInfoMessageToUI((RECONNECT_TIME / 1000) + "秒后再尝试连接");try {wait(RECONNECT_TIME);reconnect();} catch (InterruptedException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}}}private void close() {state = connect;try {if (socket != null) {socket.close();socket = null;}if(input!=null){input.close();input=null;}if(output!=null){ output.close(); output=null;}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}

                      6.ProtocolConst.class:

public class ProtocolConst { protected static final String ip = "192.168.1.167";protected static final int port = 4321;}

                       7.BootReceiver.class:

public class BootReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent arg1) {// TODO Auto-generated method stub        context.startService(new Intent(context, IMService.class));}}
            

                       8.MainActivity.class:

public class MainActivity extends Activity implements OnClickListener{    /** Called when the activity is first created. */EditText username;EditText socketAddress;EditText showContent;Button connectButton;Button  disconnectButton;Button quitButton;Button sendButton;EditText sendContent;String nameValue;String addressValue;    public static final String reconnectTag="reconnect";    SocketAddress address;    ReceiverHandler rh;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);                username=(EditText)this.findViewById(R.id.username);        socketAddress=(EditText)this.findViewById(R.id.serveraddress);        showContent=(EditText)this.findViewById(R.id.showcontent);        sendContent=(EditText)this.findViewById(R.id.sendcontent);        connectButton=(Button)this.findViewById(R.id.connect);        disconnectButton=(Button)this.findViewById(R.id.disconnect);        quitButton=(Button)this.findViewById(R.id.quit);        sendButton=(Button)this.findViewById(R.id.send);                sendContent.setOnClickListener(this);        connectButton.setOnClickListener(this);        disconnectButton.setOnClickListener(this);        quitButton.setOnClickListener(this);        sendButton.setOnClickListener(this);                findViewById(R.id.send_code).setOnClickListener(this);        findViewById(R.id.send_close_code).setOnClickListener(this);                this.startService(new Intent(this, IMService.class));    }        public class ReceiverHandler extends BroadcastReceiver{    Context context=null;    public ReceiverHandler(Context context)    {    this.context=context;    }        public void registerAction(String action){            IntentFilter filter=new IntentFilter();            filter.addAction(action);            context.registerReceiver(this, filter);        }            @Override        public void onReceive(Context context, Intent intent) {        if(intent.getAction().equals(IMService.messageTag))        {        String message=intent.getStringExtra("message");        Message mess=new Message();        mess.obj=message;        handler.sendMessage(mess);        }        }    }        public Handler handler= new Handler()    {    public void handleMessage(Message msg) {    String message=msg.obj.toString();    showContent.append(message);    }    };@Overrideprotected void onStart() {// TODO Auto-generated method stubsuper.onStart();rh=new ReceiverHandler(this);rh.registerAction(IMService.messageTag);}@Overrideprotected void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();unregisterReceiver(rh);}public static final String FLAG_PLAYER_VIDEO="0";public static final String FLAG_CREATE_CODE="1";public static final String FLAG_CLOSE_CODE="2";public static String createPar(String productId)     {  String ret="";  JSONObject menu = new JSONObject();  try {menu.put("flag", FLAG_PLAYER_VIDEO);menu.put("msg", "播放商品视频");menu.put("productId", productId);  ret=menu.toString(); } catch (JSONException e) {// TODO Auto-generated catch blocke.printStackTrace();}  return ret;     }  public static String createCodePar(String productId){ String ret="";  JSONObject menu = new JSONObject();  try {menu.put("flag", FLAG_CREATE_CODE);menu.put("msg", "显示商品二维码");menu.put("productId", productId);  ret=menu.toString(); } catch (JSONException e) {// TODO Auto-generated catch blocke.printStackTrace();}  return ret; }    public static String closeCodePar(){ String ret="";  JSONObject menu = new JSONObject();  try {menu.put("flag", FLAG_CLOSE_CODE);menu.put("msg", "关闭商品二维码");menu.put("productId", null); ret=menu.toString(); } catch (JSONException e) {// TODO Auto-generated catch blocke.printStackTrace();}  return ret; }  public static String getProductID(String str){ String ret="";  if(str!=null&&!str.equals("")){ try {JSONObject obj=new JSONObject(str);ret=obj.getString("productId");} catch (JSONException e) {// TODO Auto-generated catch blocke.printStackTrace();} } return ret; }@Overridepublic void onClick(View v) {// TODO Auto-generated method stubString text;switch(v.getId()){case R.id.send:            text=sendContent.getText().toString();if(text!=null&&!text.equals("")){text=createPar(text)+"\n";Log.i("text", text);IMService.addPacket(text);IMService.wakeUp();            sendContent.setText("");}break;case R.id.send_code:    text=sendContent.getText().toString();if(text!=null&&!text.equals("")){text=createCodePar(text)+"\n";Log.i("text", text);IMService.addPacket(text);IMService.wakeUp();            sendContent.setText("");}break;case R.id.send_close_code:text=closeCodePar()+"\n";Log.i("text", text);IMService.addPacket(text);IMService.wakeUp();break;}}}


                    10.main.xml:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <LinearLayout        android:id="@+id/linearLayout1"        android:layout_width="fill_parent"        android:layout_height="wrap_content" >        <TextView            android:id="@+id/textView3"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="@string/Name" />        <EditText            android:id="@+id/username"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1" >            <requestFocus />        </EditText>    </LinearLayout>    <LinearLayout        android:id="@+id/linearLayout2"        android:layout_width="fill_parent"        android:layout_height="wrap_content" >        <TextView            android:id="@+id/textView2"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="@string/Server" />        <EditText            android:id="@+id/serveraddress"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1" />    </LinearLayout>    <LinearLayout        android:id="@+id/linearLayout4"        android:layout_width="fill_parent"        android:layout_height="340dp"        android:layout_gravity="bottom" >        <EditText            android:id="@+id/showcontent"            android:layout_width="268dp"            android:layout_height="fill_parent"            android:inputType="textMultiLine" />        <LinearLayout            android:id="@+id/linearLayout5"            android:layout_width="wrap_content"            android:layout_height="fill_parent"            android:gravity="center"            android:orientation="vertical" >            <Button                android:id="@+id/connect"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="@string/Connect" />            <Button                android:id="@+id/disconnect"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="@string/Disconnect" />            <Button                android:id="@+id/quit"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="@string/Quit" />        </LinearLayout>    </LinearLayout>    <LinearLayout        android:id="@+id/linearLayout6"        android:layout_width="fill_parent"        android:layout_height="wrap_content" >        <EditText            android:id="@+id/sendcontent"            android:layout_width="245dp"            android:layout_height="wrap_content"            android:layout_weight="233.73" />        <Button            android:id="@+id/send"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="0.15"            android:text="@string/Send" />                                   <Button            android:id="@+id/send_code"            android:layout_width="wrap_content"            android:layout_height="wrap_content"                      android:text="弹出二维码" />                   <Button            android:id="@+id/send_close_code"            android:layout_width="wrap_content"            android:layout_height="wrap_content"                       android:text="关闭二维码" />                   </LinearLayout>    <LinearLayout        android:id="@+id/linearLayout3"        android:layout_width="wrap_content"        android:layout_height="387dp" >    </LinearLayout></LinearLayout>

                           11.AndroidManifest.xml
<span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.gys.im"    android:versionCode="1"    android:installLocation="preferExternal"    android:versionName="1.0" >    <uses-sdk android:minSdkVersion="16" />    <uses-permission android:name="android.permission.INTERNET" />    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>     <uses-permission android:name="android.permission.VIBRATE" />    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>     <application        android:icon="@drawable/ic_launcher" android:debuggable="true"        android:label="@string/app_name" >        <activity            android:label="@string/app_name"            android:name=".MainActivity" >            <intent-filter >                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>                    <service android:name="com.gys.service.IMService"></service>              <receiver android:name="com.gys.BroadCast.BootReceiver">                  <intent-filter>                            <action android:name="android.intent.action.BOOT_COMPLETED"/>                              <category android:name="android.intent.category.HOME" />                  </intent-filter>       </receiver>                 </application></manifest></span>

                                

                             以上就是我关于Android的Socket通讯客户端的代码,下一篇中我会讲解服务端的代码,并与客户端对接。共勉.

                                                      

                                               

4 0
原创粉丝点击