乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      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é)議來(lái)傳遞信息。一方面是為了安全排除臟數(shù)據(jù),另一個(gè)方面是為了更加高效的處理自己所需要的數(shù)據(jù)。今天就來(lái)介紹一下關(guān)于socket自定義協(xié)議和使用Protocol Buffer解析數(shù)據(jù)。

      首先

      既然說(shuō)到了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語(yǔ)言中一字節(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ù)詳解(語(yǔ)言規(guī)范)今天主要講解的是socket自定義協(xié)議這塊

      其次

      說(shuō)了那么多,我們來(lái)看看我們今天的主要內(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來(lái)說(shuō)放到 service里面去是最合適的,并且為了保證連接狀態(tài)。那么,就要發(fā)送一個(gè)心跳包保證連接狀態(tài)。既然這樣,那么我們來(lá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ù),無(wú)論數(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ù)器端無(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)出來(lái)了,方便客戶端和服務(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來(lái)說(shuō),能靈活運(yùn)用,首先要感謝我們公司的同事,沒有他們提供思路,估計(jì)很難靈活運(yùn)用socket和proto buffer。其次,要感謝之前公司的大佬,還有給我提供寶貴意見的各位好友。還有要感謝自己,能靜下心來(lái),堅(jiān)持不懈,克服proto buffer和socket相結(jié)合的寫法。

      感謝

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

      來(lái)源: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)論公約

        類似文章 更多