小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Android socket高級(jí)用法(自定義協(xié)議和Protocol Buffer使用)

 印度阿三17 2019-09-11

前提

之前寫過兩篇關(guān)于socket的文章,但是,只是簡(jiǎn)單的介紹了一下關(guān)于socket Tcp和Udp的簡(jiǎn)單使用。如果沒有看過的朋友可以去看看Android Socket編程(tcp)初探Android Socket編程(udp)初探。相信很多朋友在公司使用socket開發(fā)的時(shí)候都會(huì)自定義協(xié)議來傳遞信息。一方面是為了安全排除臟數(shù)據(jù),另一個(gè)方面是為了更加高效的處理自己所需要的數(shù)據(jù)。今天就來介紹一下關(guān)于socket自定義協(xié)議和使用Protocol Buffer解析數(shù)據(jù)。

首先

既然說到了Protocol Buffer,那么我們就簡(jiǎn)單介紹一下Protocol Buffer是什么?并且使用為什么要使用Protocol Buffer?

  • 1、什么是Protocol Buffer

一種 結(jié)構(gòu)化數(shù)據(jù) 的數(shù)據(jù)存儲(chǔ)格式(類似于 XML、Json ),其作用是通過將 結(jié)構(gòu)化的數(shù)據(jù) 進(jìn)行 串行化(序列化),從而實(shí)現(xiàn) 數(shù)據(jù)存儲(chǔ) / RPC 數(shù)據(jù)交換的功能。至于更詳細(xì)的用法和介紹請(qǐng)移步Protocol Buffer 序列化原理大揭秘 - 為什么Protocol Buffer性能這么好?

  • 2、為什么要使用Protocol Buffer

    在回答這個(gè)問題之前,我們還是先給出一個(gè)在實(shí)際開發(fā)中經(jīng)常會(huì)遇到的系統(tǒng)場(chǎng)景。比如:我們的客戶端程序是使用Java開發(fā)的,可能運(yùn)行自不同的平臺(tái),如:Linux、Windows或者是Android,而我們的服務(wù)器程序通常是基于Linux平臺(tái)并使用C 或者Python開發(fā)完成的。在這兩種程序之間進(jìn)行數(shù)據(jù)通訊時(shí)存在多種方式用于設(shè)計(jì)消息格式,如:
    1、 直接傳遞C/C /Python語言中一字節(jié)對(duì)齊的結(jié)構(gòu)體數(shù)據(jù),只要結(jié)構(gòu)體的聲明為定長(zhǎng)格式,那么該方式對(duì)于C/C /Python程序而言就非常方便了,僅需將接收到的數(shù)據(jù)按照結(jié)構(gòu)體類型強(qiáng)行轉(zhuǎn)換即可。事實(shí)上對(duì)于變長(zhǎng)結(jié)構(gòu)體也不會(huì)非常麻煩。在發(fā)送數(shù)據(jù)時(shí),也只需定義一個(gè)結(jié)構(gòu)體變量并設(shè)置各個(gè)成員變量的值之后,再以char*的方式將該二進(jìn)制數(shù)據(jù)發(fā)送到遠(yuǎn)端。反之,該方式對(duì)于Java開發(fā)者而言就會(huì)非常繁瑣,首先需要將接收到的數(shù)據(jù)存于ByteBuffer之中,再根據(jù)約定的字節(jié)序逐個(gè)讀取每個(gè)字段,并將讀取后的值再賦值給另外一個(gè)值對(duì)象中的域變量,以便于程序中其他代碼邏輯的編寫。對(duì)于該類型程序而言,聯(lián)調(diào)的基準(zhǔn)是必須客戶端和服務(wù)器雙方均完成了消息報(bào)文構(gòu)建程序的編寫后才能展開,而該設(shè)計(jì)方式將會(huì)直接導(dǎo)致Java程序開發(fā)的進(jìn)度過慢。即便是Debug階段,也會(huì)經(jīng)常遇到Java程序中出現(xiàn)各種域字段拼接的小錯(cuò)誤。
    2、 使用SOAP協(xié)議(WebService)作為消息報(bào)文的格式載體,由該方式生成的報(bào)文是基于文本格式的,同時(shí)還存在大量的XML描述信息,因此將會(huì)大大增加網(wǎng)絡(luò)IO的負(fù)擔(dān)。又由于XML解析的復(fù)雜性,這也會(huì)大幅降低報(bào)文解析的性能??傊?,使用該設(shè)計(jì)方式將會(huì)使系統(tǒng)的整體運(yùn)行性能明顯下降。
    對(duì)于以上兩種方式所產(chǎn)生的問題,Protocol Buffer均可以很好的解決,不僅如此,Protocol Buffer還有一個(gè)非常重要的優(yōu)點(diǎn)就是可以保證同一消息報(bào)文新舊版本之間的兼容性。對(duì)于Protocol Buffer具體的用法請(qǐng)移步Protocol Buffer技術(shù)詳解(語言規(guī)范)今天主要講解的是socket自定義協(xié)議這塊

其次

說了那么多,我們來看看我們今天的主要內(nèi)容— 自定義socket協(xié)議
先看一張心跳返回的圖

心跳返回.png

  • 1、Protobuf協(xié)議

  • 假設(shè)客戶端請(qǐng)求包體數(shù)據(jù)協(xié)議如下

request.proto

syntax = "proto3";
// 登錄的包體數(shù)據(jù)
message Request {
 int32   uid = 0;
string  api_token = 1;
}

發(fā)送的格式:

{包頭}{命令}{包體}
{包頭} -> 包體轉(zhuǎn)成protubuf的長(zhǎng)度
{命令} -> 對(duì)應(yīng)功能的命令字參數(shù)
{包體} -> 對(duì)應(yīng)的protubuf數(shù)據(jù)

  • 假設(shè)服務(wù)端返回包體數(shù)據(jù)協(xié)議

response.proto

syntax = "proto3";
// 登錄成功后服務(wù)器返回的包體數(shù)據(jù)
message Response {
int32   login = 1;
}

服務(wù)器返回的格式:

{包頭}{命令}{狀態(tài)碼}{包體}
{包頭} -> 包體轉(zhuǎn)成protubuf的長(zhǎng)度
{命令} -> 對(duì)應(yīng)功能的命令字參數(shù)
{狀態(tài)碼} -> 對(duì)應(yīng)狀態(tài)的狀態(tài)碼
{包體} -> 對(duì)應(yīng)的protubuf數(shù)據(jù)

  • 2、客戶端socket寫法

  • 分析:試想一下,要socket不會(huì)因?yàn)槭謾C(jī)屏幕的熄滅或者其他什么的而斷開,我們應(yīng)該把socket放到哪里去寫,又要怎么保證socket的連接狀態(tài)呢?對(duì)于Android來說放到 service里面去是最合適的,并且為了保證連接狀態(tài)。那么,就要發(fā)送一個(gè)心跳包保證連接狀態(tài)。既然這樣,那么我們來寫service和socket。

  • 3、service寫法

     public class SocketService extends Service {
    
      Thread mSocketThread;
      Socket mSocket;
      InetSocketAddress mSocketAddress;
      //心跳線程
       Thread mHeartThread;
      //接收線程
      Thread mReceiveThread;
       //登錄線程
      Thread mLoginThread;
       boolean isHeart = false;
       boolean isReceive = false;
    
    SocketBinder mBinder = new SocketBinder(this);
    
    public SocketService() {
    
    }
    
    @Override
    public void onCreate() {
       super.onCreate();
       createConnection();
       receiveMsg();
       isHeart = true;
       isReceive = true;
    }
    
    
    @Override
    public IBinder onBind(Intent intent) {
     return mBinder;
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
     startGps();
     sendHeart();
     if (!TextUtils.isEmpty(intent.getStringExtra(AppConfig.SERVICE_TAG))) {
         String TAG = intent.getStringExtra(AppConfig.SERVICE_TAG);
         switch (TAG) {
             case AppConfig.STOP_SERVICE_VALUE: {//停止服務(wù)
                 ClientSocket.getsInstance().shutDownConnection(mSocket);
                 stopSelf();
                 mSocket = null;
                 mHeartThread = null;
                 mReceiveThread = null;
                 mLoginThread = null;
                 mSocketThread = null;
                 isHeart = false;
                 isReceive = false;
                 break;
             }
            
             default:
                 break;
         }
     }
     return super.onStartCommand(intent, flags, startId);
    
     }
    
    
    /**
     * 發(fā)送心跳包
     */
    private void sendHeart() {
     mHeartThread = new Thread(new Runnable() {
         @Override
         public void run() {
             while (isHeart) {
                 ClientSocket.getsInstance().sendHeart(mSocket, SocketStatus.HEART_CODE);
                 try {
                     Thread.sleep(1000);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         }
     });
     mHeartThread.start();
     }
    
     /**
      * 登錄
      */
     private void login(final double mLatitude, final double mLongitude) {
       mLoginThread = new Thread(new Runnable() {
         @Override
         public void run() {
             if (PreferencesUtils.getInt(SocketService.this, Constants.USER_ID) != 0 &&
                     !TextUtils.isEmpty(PreferencesUtils.getString(SocketService.this,
                             Constants.USER_TOKEN))) {
                 Request.Request requestLogin =
                         Request.Request.newBuilder()
                                 .setUid(PreferencesUtils.getInt(SocketService.this,
                                         Constants.USER_ID))
                                 .setApiToken(PreferencesUtils.getString(SocketService.this,
                                         Constants.USER_TOKEN).trim())
                                 .build();
                
                 ClientSocket.getsInstance().sendLogin(mSocket, requestLogin, SocketStatus.LOGIN_CODE);
             
             }
         }
       });
       mLoginThread.start();
    
     }
    
    /**
     * 創(chuàng)建連接
     *
     * @return
     */
     public void createConnection() {
     mSocketThread = new Thread(new Runnable() {
         @Override
         public void run() {
             try {
                 mSocket = new Socket();
                 mSocketAddress = new InetSocketAddress(AppConfig.TCP_IP, AppConfig.TCP_PORT);
                 mSocket.connect(mSocketAddress, 20 * 1000);
                 // 設(shè)置 socket 讀取數(shù)據(jù)流的超時(shí)時(shí)間
                 mSocket.setSoTimeout(20 * 1000);
                 // 發(fā)送數(shù)據(jù)包,默認(rèn)為 false,即客戶端發(fā)送數(shù)據(jù)采用 Nagle 算法;
                 // 但是對(duì)于實(shí)時(shí)交互性高的程序,建議其改為 true,即關(guān)閉 Nagle
                 // 算法,客戶端每發(fā)送一次數(shù)據(jù),無論數(shù)據(jù)包大小都會(huì)將這些數(shù)據(jù)發(fā)送出去
                 mSocket.setTcpNoDelay(true);
                 // 設(shè)置客戶端 socket 關(guān)閉時(shí),close() 方法起作用時(shí)延遲 30 秒關(guān)閉,如果 30 秒內(nèi)盡量將未發(fā)送的數(shù)據(jù)包發(fā)送出去
                 // socket.setSoLinger(true, 30);
                 // 設(shè)置輸出流的發(fā)送緩沖區(qū)大小,默認(rèn)是4KB,即4096字節(jié)
                 mSocket.setSendBufferSize(10 * 1024);
                 // 設(shè)置輸入流的接收緩沖區(qū)大小,默認(rèn)是4KB,即4096字節(jié)
                 mSocket.setReceiveBufferSize(10 * 1024);
                 // 作用:每隔一段時(shí)間檢查服務(wù)器是否處于活動(dòng)狀態(tài),如果服務(wù)器端長(zhǎng)時(shí)間沒響應(yīng),自動(dòng)關(guān)閉客戶端socket
                 // 防止服務(wù)器端無效時(shí),客戶端長(zhǎng)時(shí)間處于連接狀態(tài)
                 mSocket.setKeepAlive(true);
             } catch (UnknownHostException e) {
                 Logger.e(e.getMessage()   "======== UnknownHostException");
                 e.printStackTrace();
             } catch (IOException e) {
                 createConnection();
                 Logger.e(e.getMessage()   "========IOException");
                 e.printStackTrace();
             } catch (NetworkOnMainThreadException e) {
                 Logger.e(e.getMessage()   "========NetworkOnMainThreadException");
                 e.printStackTrace();
             }
         }
     });
     mSocketThread.start();
    }
    
    
    /**
     * 接收
     */
    private void receiveMsg() {
     mReceiveThread = new Thread(new Runnable() {
         @Override
         public void run() {
             while (isReceive) {
                 try {
                     if (mSocket != null && mSocket.isConnected()) {
                         DataInputStream dis = ClientSocket.getsInstance().getMessageStream(mSocket);
                         ByteArrayOutputStream bos = new ByteArrayOutputStream();
                         if (dis != null) {
                             int length = 0;
                             int head = 0;
                             int buffer_size = 4;
                             byte[] headBuffer = new byte[4];
                             byte[] cmdBuffer = new byte[4];
                             byte[] stateBuffer = new byte[4];
                             length = dis.read(headBuffer, 0, buffer_size);
                             if (length == 4) {
                                 bos.write(headBuffer, 0, length);
                                 System.arraycopy(bos.toByteArray(), 0, headBuffer, 0, buffer_size);
                                 head = ByteUtil.bytesToInt(headBuffer, 0);
                                 length = dis.read(cmdBuffer, 0, buffer_size);
                                 bos.write(cmdBuffer, 0, length);
                                 System.arraycopy(bos.toByteArray(), 4, cmdBuffer, 0, buffer_size);
                                 int cmd = ByteUtil.hexStringToAlgorism(ByteUtil.str2HexStr(ByteUtil.byte2hex(cmdBuffer)));
                                 int heartNumber = ByteUtil.hexStringToAlgorism(ByteUtil.str2HexStr(SocketStatus.HEART));
                                 String discover = Integer.toHexString(0x0101);
                                 int discoverNumber = ByteUtil.hexStringToAlgorism(ByteUtil.str2HexStr(SocketStatus.DISCOVER));
                                 int giftNumber = ByteUtil.hexStringToAlgorism(ByteUtil.str2HexStr(SocketStatus.GIFT));
                                 if (cmd == heartNumber) {
                                     length = dis.read(stateBuffer, 0, buffer_size);
                                     bos.write(stateBuffer, 0, length);
                                     System.arraycopy(bos.toByteArray(), 8, stateBuffer, 0, buffer_size);
                                     switch (ByteUtil.bytesToInt(stateBuffer, 0)) {
                                         case SocketStatus.LOGIN_SUCCESS: {//登錄成功
                                             Logger.e("登錄成功");
                                             mLoginValue = "1";
                                             EventUtils.sendEvent(new Event<>(Constants.MSG_LOGIN_SUCCESS));
                                             break;
                                         }
                                       
                                         case SocketStatus.HEART_SUCCESS: {//心跳返回
                                             if (ByteUtil.bytesToInt(stateBuffer, 0) == 200
                                                     && Integer.toHexString(ByteUtil.bytesToInt(cmdBuffer, 0))
                                                     .equals(discover)) {
                                                 byte[] buffer = new byte[head];
                                                 length = dis.read(buffer, 0, head);
                                                 bos.write(buffer, 0, length);
                                                 Response.Response response = Response.
                                                         Response.parseFrom(buffer);
                                                 Logger.e(responseExplore.getNickname()   responseExplore.getAvatar());
                                                 //發(fā)送到activity中對(duì)數(shù)據(jù)進(jìn)行處理
                                                 EventUtils.sendEvent(new Event<>(Constants.MSG_START_DISCOVER_RESULT,
                                                         responseExplore));
                                                 Logger.e(responseExplore   "=======response");
                                             } else {
                                                 Logger.e("心跳返回");
                                             }
                                             break;
                                         }
                                        
                                         default:
                                             break;
                                     }
                                 }
                             } else {
                                    //出錯(cuò)重連
                                 ClientSocket.getsInstance().shutDownConnection(mSocket);
                                 createConnection();
                             }
    
                         } else {
                             createConnection();
                         }
                     }
                 } catch (IOException ex) {
                     ex.printStackTrace();
                 }
                 try {
                     Thread.sleep(50);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         }
     });
     mReceiveThread.start();
    }
    
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        ClientSocket.getsInstance().shutDownConnection(mSocket);
        stopSelf();
        mHeartThread = null;
        mReceiveThread = null;
        mLoginThread = null;
        mSocketThread = null;
        mStopDiscoverThread = null;
        isHeart = false;
        isReceive = false;
     
    }
    
    
    
    
    /**
     * Binder
     */
    public class SocketBinder extends Binder {
    
     private SocketService mService;
     public OnServiceCallBack mCallBack;
    
     public SocketBinder(SocketService mService) {
         this.mService = mService;
     }
    
     /**
      * 發(fā)送方法
      *
      * @param object
      */
     public void sendMethod(Object object) {
         mService.sendMsg(object);
         mCallBack.onService(object);
     }
    
     /**
      * 設(shè)置回調(diào)
      *
      * @param callBack
      */
     public void setOnServiceCallBack(OnServiceCallBack callBack) {
         this.mCallBack = callBack;
       }
      }
    
    }
    
  • 分析
    上面的service中首先創(chuàng)建socket,然后連接,在socket發(fā)生錯(cuò)誤的時(shí)候(比如網(wǎng)絡(luò)異常)重新進(jìn)行創(chuàng)建在連接。然后,開一個(gè)接收線程一直接收,每次接收都是接收4個(gè)字節(jié)的int值進(jìn)行判斷是否可以進(jìn)入到下一步,如果可以則繼續(xù)向下。讀取4個(gè)字節(jié)的__包頭__然后讀取4個(gè)字節(jié)的__命令__ 再讀取4個(gè)字節(jié)的__狀態(tài)碼__ 最后讀取4個(gè)字節(jié)的__包體__,包體就包含我們所需要返回的數(shù)據(jù)。并且,在剛開始的時(shí)候就開啟了一個(gè)接收線程每隔50毫秒接收一次數(shù)據(jù),這樣不僅可以讀取到心跳包還可以讀取到我們需要的數(shù)據(jù)。在最后,server生命周期結(jié)束的時(shí)候停止所有的線程。

  • 4、發(fā)送數(shù)據(jù)的類

     public class ClientSocket {
     private DataOutputStream out = null;
     private DataInputStream getMessageStream;
     private static ClientSocket sInstance;
    
     private ClientSocket() {
     }
    
     /**
      * 單例
      *
      * @return
      */
     public static ClientSocket getsInstance() {
      if (sInstance == null) {
          synchronized (ClientSocket.class) {
              if (sInstance == null) {
                  sInstance = new ClientSocket();
              }
          }
      }
      return sInstance;
     }
    
    
     /**
      * 登錄
      *
      * @return
      */
     public void sendLogin(Socket socket, Request.RequestLogin requestLogin, int code) {
      byte[] data = requestLogin.toByteArray();
      byte[] head = ByteUtil.intToBytes(data.length);
      byte[] cmd = ByteUtil.intToBytes(code);
      byte[] bytes = addBytes(head, cmd, data);
      if (socket != null) {
          if (socket.isConnected()) {
              try {
                  OutputStream os = socket.getOutputStream();
                  os.write(bytes);
                  os.flush();
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      }
     }
    
    
     /**
      * 心跳
      *
      * @param code 關(guān)鍵字(命令)
      * @return
      */
     public boolean sendHeart(Socket socket, int code) {
      boolean isSuccess;
      byte[] head = ByteUtil.intToBytes(0);
      byte[] cmd = ByteUtil.intToBytes(code);
      byte[] bytes = addBytes(head, cmd);
      if (socket.isConnected()) {
          try {
              out = new DataOutputStream(socket.getOutputStream());
              out.write(bytes);
              out.flush();
              isSuccess = true;
          } catch (IOException e) {
              e.printStackTrace();
              isSuccess = false;
          }
      } else {
          isSuccess = false;
      }
      return isSuccess;
     }
    
     /**
      * 斷開連接
      */
     public void shutDownConnection(Socket socket) {
      try {
          if (out != null) {
              out.close();
          }
          if (getMessageStream != null) {
              getMessageStream.close();
          }
          if (socket != null) {
              socket.close();
          }
      } catch (IOException e) {
          e.printStackTrace();
      }
    }
    
     /**
      * 獲取服務(wù)器返回的流
      *
      * @param socket
      * @return
      */
     public DataInputStream getMessageStream(Socket socket) {
      if (socket == null) {
          return null;
      }
    
      if (socket.isClosed()) {
          return null;
      }
      if (!socket.isConnected()) {
          return null;
      }
      try {
          getMessageStream = new DataInputStream(new BufferedInputStream(
                  socket.getInputStream()));
      } catch (IOException e) {
          e.printStackTrace();
          if (getMessageStream != null) {
              try {
                  getMessageStream.close();
              } catch (IOException e1) {
                  e1.printStackTrace();
              }
          }
      }
      return getMessageStream;
      }
     }
    
  • 分析:
    這里使用了單例模式,保證了數(shù)據(jù)的唯一性,不會(huì)重復(fù)創(chuàng)建,可以看到登錄發(fā)送了包頭、命令和數(shù)據(jù)長(zhǎng)度,而心跳只是包頭和命令,因?yàn)榘w長(zhǎng)度為空,所以不用發(fā)送,最后轉(zhuǎn)成4個(gè)字節(jié)的二進(jìn)制數(shù)據(jù)進(jìn)行發(fā)送。這樣,proto buffer的優(yōu)點(diǎn)就體現(xiàn)出來了,方便客戶端和服務(wù)端的解析。

  • 二進(jìn)制轉(zhuǎn)換工具類

     public class ByteUtil {
    
     /**
      * 將2個(gè)byte數(shù)組進(jìn)行拼接
      */
     public static byte[] addBytes(byte[] data1, byte[] data2) {
      byte[] data3 = new byte[data1.length   data2.length];
      System.arraycopy(data1, 0, data3, 0, data1.length);
      System.arraycopy(data2, 0, data3, data1.length, data2.length);
      return data3;
    }
    
     /**
      * 將3個(gè)byte數(shù)組進(jìn)行拼接
      */
    public static byte[] addBytes(byte[] data1, byte[] data2, byte[] data3) {
      byte[] data4 = new byte[data1.length   data2.length   data3.length];
      System.arraycopy(data1, 0, data4, 0, data1.length);
      System.arraycopy(data2, 0, data4, data1.length, data2.length);
      System.arraycopy(data3, 0, data4, data1.length   data2.length, data3.length);
      return data4;
     }
    
     /**
      * int轉(zhuǎn)byte{}
      */
     public static byte[] intToBytes(int value, ByteOrder mode) {
      byte[] src = new byte[4];
      if (mode == ByteOrder.LITTLE_ENDIAN) {
          src[3] = (byte) ((value >> 24) & 0xFF);
          src[2] = (byte) ((value >> 16) & 0xFF);
          src[1] = (byte) ((value >> 8) & 0xFF);
          src[0] = (byte) (value & 0xFF);
      } else {
          src[0] = (byte) ((value >> 24) & 0xFF);
          src[1] = (byte) ((value >> 16) & 0xFF);
          src[2] = (byte) ((value >> 8) & 0xFF);
          src[3] = (byte) (value & 0xFF);
      }
      return src;
     }
    
    
     /**
      * 16進(jìn)制表示的字符串轉(zhuǎn)換為字節(jié)數(shù)組
      *
      * @param s 16進(jìn)制表示的字符串
      * @return byte[] 字節(jié)數(shù)組
      */
     public static byte[] hexStringToByteArray(String s) {
      int len = s.length();
      byte[] b = new byte[len / 2];
      for (int i = 0; i < len; i  = 2) {
          // 兩位一組,表示一個(gè)字節(jié),把這樣表示的16進(jìn)制字符串,還原成一個(gè)字節(jié)
          b[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)   Character
                  .digit(s.charAt(i   1), 16));
      }
      return b;
     }
    
    
     /**
      * byte數(shù)組中取int數(shù)值,本方法適用于(低位在前,高位在后)的順序,和和intToBytes()配套使用
      *
      * @param src    byte數(shù)組
      * @param offset 從數(shù)組的第offset位開始
      * @return int數(shù)值
      */
     public static int bytesToInt(byte[] src, int offset) {
      int value;
      value = (int) ((src[offset] & 0xFF)
              | ((src[offset   1] & 0xFF) << 8)
              | ((src[offset   2] & 0xFF) << 16)
              | ((src[offset   3] & 0xFF) << 24));
      return value;
      }
    
     /**
      * byte數(shù)組中取int數(shù)值,本方法適用于(低位在后,高位在前)的順序。和intToBytes2()配套使用
      */
    public static int bytesToInt2(byte[] src, int offset) {
      int value;
      value = (int) (((src[offset] & 0xFF) << 24)
              | ((src[offset   1] & 0xFF) << 16)
              | ((src[offset   2] & 0xFF) << 8)
              | (src[offset   3] & 0xFF));
      return value;
     }
    
     /**
      * 將int數(shù)值轉(zhuǎn)換為占四個(gè)字節(jié)的byte數(shù)組,本方法適用于(低位在前,高位在后)的順序。 和 
       bytesToInt()配套使用
      *
      * @param value 要轉(zhuǎn)換的int值
      * @return byte數(shù)組
      */
     public static byte[] intToBytes(int value) {
      byte[] src = new byte[4];
      src[3] = (byte) ((value >> 24) & 0xFF);
      src[2] = (byte) ((value >> 16) & 0xFF);
      src[1] = (byte) ((value >> 8) & 0xFF);
      src[0] = (byte) (value & 0xFF);
      return src;
     }
    
     /**
      * 將int數(shù)值轉(zhuǎn)換為占四個(gè)字節(jié)的byte數(shù)組,本方法適用于(高位在前,低位在后)的順序。  和 
       bytesToInt2()配套使用
      */
     public static byte[] intToBytes2(int value) {
      byte[] src = new byte[4];
      src[0] = (byte) ((value >> 24) & 0xFF);
      src[1] = (byte) ((value >> 16) & 0xFF);
      src[2] = (byte) ((value >> 8) & 0xFF);
      src[3] = (byte) (value & 0xFF);
      return src;
     }
    
     /**
      * 將字節(jié)轉(zhuǎn)換為二進(jìn)制字符串
      *
      * @param bytes 字節(jié)數(shù)組
      * @return 二進(jìn)制字符串
      */
     public static String byteToBit(byte... bytes) {
      StringBuffer sb = new StringBuffer();
      int z, len;
      String str;
      for (int w = 0; w < bytes.length; w  ) {
          z = bytes[w];
          z |= 256;
          str = Integer.toBinaryString(z);
          len = str.length();
          sb.append(str.substring(len - 8, len));
        }
        return sb.toString();
       }
    
        /**
         * 字節(jié)數(shù)組轉(zhuǎn)為普通字符串(ASCII對(duì)應(yīng)的字符)
         *
         * @param bytearray byte[]
         * @return String
         */
        public static String byte2String(byte[] bytearray) {
      String result = "";
      char temp;
    
      int length = bytearray.length;
      for (int i = 0; i < length; i  ) {
          temp = (char) bytearray[i];
          result  = temp;
      }
      return result;
     }
    
     /**
      * 二進(jìn)制字符串轉(zhuǎn)十進(jìn)制
      *
      * @param binary 二進(jìn)制字符串
      * @return 十進(jìn)制數(shù)值
      */
    public static int binaryToAlgorism(String binary) {
      int max = binary.length();
      int result = 0;
      for (int i = max; i > 0; i--) {
          char c = binary.charAt(i - 1);
          int algorism = c - '0';
          result  = Math.pow(2, max - i) * algorism;
      }
      return result;
     }
    
     /**
      * 字節(jié)數(shù)組轉(zhuǎn)換為十六進(jìn)制字符串
      *
      * @param b byte[] 需要轉(zhuǎn)換的字節(jié)數(shù)組
      * @return String 十六進(jìn)制字符串
      */
     public static String byte2hex(byte b[]) {
      if (b == null) {
          throw new IllegalArgumentException(
                  "Argument b ( byte array ) is null! ");
      }
      String hs = "";
      String stmp = "";
      for (int n = 0; n < b.length; n  ) {
          stmp = Integer.toHexString(b[n] & 0xff);
          if (stmp.length() == 1) {
              hs = hs   "0"   stmp;
          } else {
              hs = hs   stmp;
          }
      }
      return hs.toUpperCase();
    }
    
     /**
      * 十六進(jìn)制字符串轉(zhuǎn)換十進(jìn)制
      *
      * @param hex 十六進(jìn)制字符串
      * @return 十進(jìn)制數(shù)值
      */
    public static int hexStringToAlgorism(String hex) {
      hex = hex.toUpperCase();
      int max = hex.length();
      int result = 0;
      for (int i = max; i > 0; i--) {
          char c = hex.charAt(i - 1);
          int algorism = 0;
          if (c >= '0' && c <= '9') {
              algorism = c - '0';
          } else {
              algorism = c - 55;
          }
          result  = Math.pow(16, max - i) * algorism;
      }
      return result;
     }
    
    /**
     * 字符串轉(zhuǎn)換成十六進(jìn)制字符串
     *
     * @param str 待轉(zhuǎn)換的ASCII字符串
     * @return String 每個(gè)Byte之間空格分隔,如: [61 6C 6B]
     */
     public static String str2HexStr(String str) {
    
      char[] chars = "0123456789ABCDEF".toCharArray();
      StringBuilder sb = new StringBuilder("");
      byte[] bs = str.getBytes();
      int bit;
    
      for (int i = 0; i < bs.length; i  ) {
          bit = (bs[i] & 0x0f0) >> 4;
          sb.append(chars[bit]);
          bit = bs[i] & 0x0f;
          sb.append(chars[bit]);
          sb.append(' ');
      }
      return sb.toString().trim();
     }
    
     /**
      * 16進(jìn)制轉(zhuǎn)換成字符串
      *
      * @param hexStr
      * @return
      */
     public static String hexStr2Str(String hexStr) {
      String str = "0123456789ABCDEF";
      char[] hexs = hexStr.toCharArray();
      byte[] bytes = new byte[hexStr.length() / 2];
      int n;
    
      for (int i = 0; i < bytes.length; i  ) {
          n = str.indexOf(hexs[2 * i]) * 16;
          n  = str.indexOf(hexs[2 * i   1]);
          bytes[i] = (byte) (n & 0xff);
      }
      return new String(bytes);
     }
    
    /**
     * 重寫了Inpustream 中的skip(long n) 方法,
     * 將數(shù)據(jù)流中起始的n 個(gè)字節(jié)跳過
     */
    public static long skipBytesFromStream(InputStream inputStream, long n) {
      long remaining = n;
      // SKIP_BUFFER_SIZE is used to determine the size of skipBuffer
      int SKIP_BUFFER_SIZE = 2048;
      // skipBuffer is initialized in skip(long), if needed.
      byte[] skipBuffer = null;
      int nr = 0;
      if (skipBuffer == null) {
          skipBuffer = new byte[SKIP_BUFFER_SIZE];
      }
      byte[] localSkipBuffer = skipBuffer;
      if (n <= 0) {
          return 0;
      }
      while (remaining > 0) {
          try {
              nr = inputStream.read(localSkipBuffer, 0,
                      (int) Math.min(SKIP_BUFFER_SIZE, remaining));
          } catch (IOException e) {
              e.printStackTrace();
          }
          if (nr < 0) {
              break;
          }
          remaining -= nr;
      }
      return n - remaining;
    }
    }
    

最后

對(duì)于socket和 proto buffer來說,能靈活運(yùn)用,首先要感謝我們公司的同事,沒有他們提供思路,估計(jì)很難靈活運(yùn)用socket和proto buffer。其次,要感謝之前公司的大佬,還有給我提供寶貴意見的各位好友。還有要感謝自己,能靜下心來,堅(jiān)持不懈,克服proto buffer和socket相結(jié)合的寫法。

感謝

Protocol Buffer技術(shù)詳解(語言規(guī)范)
Protocol Buffer 序列化原理大揭秘 - 為什么Protocol Buffer性能這么好?

來源:https://www./content-4-448701.html

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多