TCP长连接+心跳包

import android.os.Bundle;
import android.text.TextUtils;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import com.ysl.socket.broad.SockeBroadcastReceiver;
import com.ysl.socket.interfaces.SocketCallback;

import android.app.Activity;
import android.content.IntentFilter;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
   
   public static String str = "first message...";
   private SockeBroadcastReceiver mHeartBeatBroadCast;
   private TextView txtMsg;  
   private Button send;  
   private EditText etMsg;  
   private String content;  
   
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_socket);  
      socketTest();
   }
   
   @Override
   protected void onResume()
   {
      super.onResume();
      IntentFilter mIntentFilter = new IntentFilter();
      mIntentFilter.addAction(SockeBroadcastReceiver.HEART_BEAT_ACTION);
      mIntentFilter.addAction(SockeBroadcastReceiver.MESSAGE_ACTION);
      registerReceiver(mHeartBeatBroadCast, mIntentFilter);
   }
   
   @Override
   protected void onDestroy()
   {
      super.onDestroy();
      unregisterReceiver(mHeartBeatBroadCast);
   }
   
   //***socke测试 start*****************
   private void socketTest(){
        txtMsg = (TextView) findViewById(R.id.txt1);  
        txtMsg.setMovementMethod(ScrollingMovementMethod.getInstance());  //滚动条
        
        send = (Button) findViewById(R.id.send);  
        etMsg = (EditText) findViewById(R.id.ed1);  
        send.setOnClickListener(new OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                content = etMsg.getText().toString();
                content = "FE0099CF010A01005243FE";
                if (TextUtils.isEmpty(content)){
               Toast.makeText(MainActivity.this, "消息不能为空", Toast.LENGTH_SHORT).show();
                 return;
              }
                boolean sendState = mHeartBeatBroadCast.sendMsg(content);
                if (sendState){
               Toast.makeText(MainActivity.this, "SendSuccess", Toast.LENGTH_SHORT).show();
               setMessages("客户端发送消息:"+content);
//                 etMsg.setText("");
            }else{
               Toast.makeText(MainActivity.this, "SendFail", Toast.LENGTH_SHORT).show();
            }
            }  
        });
        
        mHeartBeatBroadCast = new SockeBroadcastReceiver(this);
      setMessages("正在连接到服务器(" + mHeartBeatBroadCast.HOST + ":" + mHeartBeatBroadCast.PORT  +  ")...");
      mHeartBeatBroadCast.setSocketCallback(new SocketCallback()
      {
         @Override
         public void connected()
         {
            Log.i("ysl", "服务器连接了...");
            runOnUiThread(new Runnable()
            {
               @Override
               public void run()
               {
                  setMessages("已连接到服务器...");
               }
            });
         }  
         @Override
         public void disConnected(){
            Log.i("ysl", "服务器断开了...");
            runOnUiThread(new Runnable()
            {
               @Override
               public void run()
               {
                  setMessages("服务器断开,自动重连中...");
               }
            });
            mHeartBeatBroadCast.initSocket();
         }
         @Override
         public void receiveMessage(String message)
         {
            Log.i("ysl", "收到新消息:" + message);
            setMessages("JAVA服务端: " + message);
         }
      });
   }
   
   /**
    * 设置TextView文本
    * @param message
    */
   public void setMessages(String message){
      txtMsg.append(message + "\n");
//    txtMsg.setText(txtMsg.getText().toString() + "\n" + message);
      int offset = txtMsg.getLineCount() * txtMsg.getLineHeight();
      if(offset > txtMsg.getHeight()){
         txtMsg.scrollTo(0,offset-txtMsg.getHeight());
      }
   }
}

 

 

 

 


/**
 * 模拟服务器  可直接运行

 */
public class AndroidService
{
   
   public static void main(String[] args) throws IOException
   {
      ServerSocket serivce = new ServerSocket(6000);
//    System.out.println("服务器已运行...");
      System.out.print("服务器已经运行======");
        while (true) {  
            //等待客户端连接  
            Socket socket = serivce.accept();  
            new Thread(new AndroidRunable(socket)).start();  
        } 
   }
}

 

**
 * 测试socket用的线程
 */
public class AndroidRunable implements Runnable
{

   Socket socket = null;
   String str = "ok";

   public AndroidRunable(Socket socket)
   {
      this.socket = socket;
   }

   @Override
   public void run()
   {
      // 向android客户端输出hello worild
      String line = null;
      InputStream input;
      OutputStream output;
      try
      {
         // 向客户端发送信息
         output = socket.getOutputStream();
         input = socket.getInputStream();
         byte[] buffer = new byte[1024 * 4];
         int length = 0;
//       output.write(str.getBytes("UTF-8"));
//       output.flush();
         // 半关闭socket
//       socket.shutdownOutput();
         //获取客户端发来的信息
         while (!socket.isClosed() && ((length = input.read(buffer)) != -1))
         {
            String message = null;
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD) {
               message = new String(Arrays.copyOf(buffer, length)).trim();
            }
            System.out.print("服务器接收到的消息:\n" + message + "\n");
            if ("xt".equals(message))  //收到心跳
            {
               output.write("收到心跳".getBytes("UTF-8"));
               output.flush();
            }
         }
         // 关闭输入输出流
         output.close();
         input.close();
         socket.close();

      } catch (IOException e)
      {
         e.printStackTrace();
      }

   }
   /**
    * input-->string
    * @param in
    * @return
    * @throws IOException
    */
   public static String inputStream2String(InputStream in) throws IOException
   {
      StringBuffer out = new StringBuffer();
      byte[] b = new byte[4096];
      int n;
      while ((n = in.read(b)) != -1)
      {
         out.append(new String(b, 0, n));
      }
      return out.toString();
   }
}

 

 

/**
 * Socket长链接核心类
 * 1.定时与服务器心跳保持(时间可以自定义)
 * 2.断线自动重连
 * 3.连接成功、断开连接、收到消息回调处理
 * 4.消息发送状态获取(成功true or 失败false)
 * 5.注册广播
 */
public class SockeBroadcastReceiver extends BroadcastReceiver
{
   private static final String TAG = "ysl";
   /** 心跳检测时间 */
   private static final long HEART_BEAT_RATE = 3 * 1000;
   /** 主机IP地址 */
   public static final String HOST = "192.168.0.1";
// public static final String HOST = "101.200.191.35";

   /** 端口号 */
   public static final int PORT = 6000;
   /** 超时设置 **/
   public static final int SOCKET_TIME_OUT = 10 * 1000;
   /** 消息广播 */
   public static final String MESSAGE_ACTION = "com.ysl.message_ACTION";
   /** 心跳广播 */
   public static final String HEART_BEAT_ACTION = "com.ysl.heart_beat_ACTION";
   /** 线程池 **/
   private ExecutorService executorService = Executors.newFixedThreadPool(5);
   /** 为了节省开销:如果最后发送时间间隔不超过心跳时间则不发心跳 */
   private long sendTime = 0L;

   private ReadThread mReadThread;
   private MainActivity mMainActivity;
   private Socket socket;
   private boolean isConnected = true; //是否处于连接状态
   private SocketCallback callback; // 回调

   /**
    * 初始化
    * @param mMainActivity
    */
   public SockeBroadcastReceiver(MainActivity mMainActivity)
   {
      this.mMainActivity = mMainActivity;
      initSocket();
   }

   /**
    * 设置状态回调
    * @param callback
    */
   public void setSocketCallback(SocketCallback callback){
      this.callback = callback;
   }

   /**
    * 初始化Socake
    */
   public void initSocket()
   {
      executorService.execute(new Runnable()
      {
         @Override
         public void run()
         {
            try
            {
               socket = new Socket();
               SocketAddress socAddress = new InetSocketAddress(HOST,PORT);
               socket.connect(socAddress, SOCKET_TIME_OUT);
               if (callback != null)  //链接成功
               {  
                  isConnected = true;
                  callback.connected();
               }
               mReadThread = new ReadThread();
               mReadThread.start();
               mHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE);// 初始化成功后,就准备发送心跳包
            } catch (UnknownHostException e)
            {
               if (callback != null)  //链接失败
               {  
                  isConnected = false;
                  callback.disConnected();
               }
               e.printStackTrace();
            } catch (IOException e)
            {
               if (callback != null)  //链接失败
               {  
                  isConnected = false;
                  callback.disConnected();
               }
               e.printStackTrace();
            }
         }
      });
      
   }

   @Override
   public void onReceive(Context context, Intent intent)
   {
      String action = intent.getAction();
      if (action.equals(MESSAGE_ACTION)){ // 消息广播
         String stringExtra = intent.getStringExtra("message");
//       Log.i(TAG, "收到服务器消息:" + stringExtra);
         if (callback != null)
         {
            callback.receiveMessage(stringExtra);
         }
      } else if (action.equals(HEART_BEAT_ACTION)){// 心跳广播
         Log.i("ysl", "收到服务器正常心跳。");
      }

   }

   /**
    * 发送心跳包
    */
   private Handler mHandler = new Handler();
   private Runnable heartBeatRunnable=new Runnable(){
      @Override 
      public void run(){
         if(System.currentTimeMillis()-sendTime>=HEART_BEAT_RATE){
//          boolean isSuccess=sendMsg("xt");// 可以随意与服务器定义好内容。。。
            boolean isSuccess=sendMsg("FE0099CF010B0114000031303038303030313135343630353238303296A1FE");// 可以随意与服务器定义好内容。。。

            if(!isSuccess){ // 如果发送不成功重连
               mHandler.removeCallbacks(heartBeatRunnable);
               mReadThread.release();
               releaseLastSocket(socket);
               if (callback != null)
               {
                  callback.disConnected();
               }
            }
         }
            mHandler.postDelayed(this,HEART_BEAT_RATE);
         }
      };

   /**
    * 发送消息
    * @param msg
    * @return
    */
   public boolean sendMsg(String msg)
   {
      if (null == socket){
         return false;
      }
      try
      {
         if (!socket.isClosed() && !socket.isOutputShutdown() && isConnected)
         {
            OutputStream os = socket.getOutputStream();
            String message = msg;
//          +"\r\n";
//          os.write(message.getBytes());
            os.write(toBytes(msg));

            os.flush();
            sendTime = System.currentTimeMillis();// 每次发送成功数据,就改一下最后成功发送的时间,节省心跳间隔时间
            Log.i(TAG, "发送成功的时间:" + sendTime);
         } else
         {
            return false;
         }
      } catch (IOException e)
      {
         e.printStackTrace();
         return false;
      }
      return true;
   }

   /**
    * 将16进制字符串转换为byte[]
    *  FE0099CF010A01005243FE
    * @param str
    * @return
    */
   public static byte[] toBytes(String str) {
      if(str == null || str.trim().equals("")) {
         return new byte[0];
      }

      byte[] bytes = new byte[str.length() / 2];
      for(int i = 0; i < str.length() / 2; i++) {
         String subStr = str.substring(i * 2, i * 2 + 2);
         bytes[i] = (byte) Integer.parseInt(subStr, 16);
      }

//        Log.e("tag1",BytesHexStrTranslate.bytesToHexFun1(bytes)+"");
//        Log.e("tag1111111", bytes + "");
      return bytes;
   }

   /**
    * 释放socket
    * @param mSocket
    */
   private void releaseLastSocket(Socket mSocket)
   {
      try
      {
         if (null != mSocket)
         {
            if (!mSocket.isClosed())
            {
               mSocket.close();
            }
            mSocket = null;
         }
      } catch (IOException e)
      {
         e.printStackTrace();
      }
   }

   /**
    * 接收消息
    */
   public class ReadThread extends Thread
   {
      private boolean isStart = true;
      public void release()
      {
         isStart = false;
         releaseLastSocket(socket);
      }

      @SuppressLint("NewApi")
      @Override
      public void run()
      {
         if (null != socket && isConnected)
         {
            try
            {
               InputStream is = socket.getInputStream();
               byte[] buffer = new byte[1024 * 4];
               int length = 0;
               while (!socket.isClosed() && !socket.isInputShutdown() && isStart && ((length = is.read(buffer)) != -1))
               {
                  isConnected = true;
                  if (length > 0)
                  {
                     String message = new String(Arrays.copyOf(buffer, length)).trim();
                     // 收到服务器过来的消息,就通过Broadcast发送出去
                     if (message.equals("ok"))
                     {// 处理心跳回复
                        Intent intent = new Intent(HEART_BEAT_ACTION);
                        mMainActivity.sendBroadcast(intent);
                     } else
                     { // 其他消息回复
                        Intent intent = new Intent(MESSAGE_ACTION);
                        intent.putExtra("message", message);
                        mMainActivity.sendBroadcast(intent);
                     }
                  }
               }
               isConnected = false;
               if (callback != null)
               {
                  callback.disConnected();
               }
            } catch (IOException e)
            {
               isConnected = false;
               if (callback != null)
               {
                  callback.disConnected();
               }
               e.printStackTrace();
               Log.i("ysl", "已经断开IOException...");
            }
         }
      }
   }
}

 

 

public interface SocketCallback
{
   void connected();
   void disConnected();
   void receiveMessage(String message);
}

 

Demo 

https://download.csdn.net/download/csdndouniwan/10897812

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值