您好,登錄后才能下訂單哦!
本篇內容主要講解“Android怎么使用socket進行二進制流數據傳輸”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Android怎么使用socket進行二進制流數據傳輸”吧!
我們自定義一個簡單的通信協議,協議一共傳輸兩種信息,第一種是文字,第二種是二進制流(其實文字也可以用二進制流表示),傳輸過程如下圖所示。
我們定義的簡單通信協議規則如下
1.首先發送一個字節的信息(就是圖中的type),表示一段消息的開始,同時也表明了后面二進制數據的類型(文字信息還是二進制流數據)
2.每一個chunk都由三個字節的長度信息和相應的二進制流信息組成,接收方在接收到三個字節的長度信息后,繼續使用相應大小的緩沖區接收后面的流數據
3.當接收到三個字節的000的時候表示數據接收完成,接收方將二進制流數據拼接起來即可
我們規定一個最大的分段長度,一旦發送的數據超過這個分段長度就需要進行分段發送。
發送的代碼示例如下
// 發送文件 public void sendFile(int size) { new Thread(()->{ try { // 表示發送文件 outputStream.write("2".getBytes()); } catch (IOException e) { e.printStackTrace(); } for(int i=0; i<size/SocketUtil.MAX_CHUNK+1; i++) { StringBuffer sb = new StringBuffer(); if (i!=size / SocketUtil.MAX_CHUNK) { for (int j = 0; j < SocketUtil.MAX_CHUNK; j++) { sb.append('a'); } } else if(i==size/SocketUtil.MAX_CHUNK && size%SocketUtil.MAX_CHUNK==0) { break; } else { for (int j = 0; j < size % SocketUtil.MAX_CHUNK; j++) { sb.append('a'); } } try { SocketUtil.sendInfo("[客戶端]發送一個數據包,大小" + sb.toString().getBytes().length + "B"); // 發送chunk的長度 outputStream.write(SocketUtil.intToStr(sb.toString().getBytes().length).getBytes()); // 發送chunk塊 outputStream.write(sb.toString().getBytes()); } catch (IOException e) { e.printStackTrace(); } } // 最后發送000表示結束 try { outputStream.write("000".getBytes()); } catch (IOException e) { e.printStackTrace(); } }).start(); }
接收二進制流的代碼示例如下
// 讀取二進制信息 public static byte[] readBytes(InputStream inputStream, String log) { byte[] len = new byte[3]; byte[] allbytes = new byte[10000]; int idx = 0; try { inputStream.read(len); // 然后再根據讀取的長度信息讀取二進制流 // 只要不是最后一個二進制流就繼續讀取 while (SocketUtil.parseLen(len) != 0) { byte[] temp = new byte[SocketUtil.parseLen(len)]; inputStream.read(temp); idx = SocketUtil.appendBytes(allbytes, temp, idx); String info = "[" + log + "]接收一個數據包,大小" + SocketUtil.parseLen(len) + "B"; SocketUtil.sendInfo(info); inputStream.read(len); } } catch (IOException e) { e.printStackTrace(); } return SocketUtil.getNewArr(allbytes, idx); }
其實我理解的所謂的通信協議,就是發送方和接收方都遵守的某種規則,按照這種規則發送和接收數據就可以保證數據的完整性。
這段代碼只有四個java文件,非常簡單,只是一個極簡的通信協議模型。
首先來看一下界面定義
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <EditText android:id="@+id/text_file_size" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="請輸入待發送文件大小"/> <Button android:id="@+id/button_send" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="發送文件"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="消息欄:"/> <TextView android:id="@+id/text_info" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
然后是MainActivity
public class MainActivity extends AppCompatActivity { private EditText text_file_size; private Button button_send; private TextView text_info; private BroadcastReceiver broadcastReceiver; private SocketClient socketClient; private SocketServer socketServer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); SocketUtil.context = MainActivity.this; // 初始化控件 initView(); // 注冊廣播接收器 register(); socketServer = new SocketServer(); socketClient = new SocketClient(); } private void initView() { text_file_size = findViewById(R.id.text_file_size); button_send = findViewById(R.id.button_send); button_send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Integer size = Integer.parseInt(text_file_size.getText().toString()); socketClient.sendFile(size); } }); text_info = findViewById(R.id.text_info); text_info.setMovementMethod(new ScrollingMovementMethod()); } private void register() { broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String info = intent.getStringExtra("info"); text_info.append(info + "\n"); } }; IntentFilter filter = new IntentFilter("main.info"); registerReceiver(broadcastReceiver, filter); } }
我們將需要重復用到的一些代碼都放到工具類中
public class SocketUtil { public static Context context; // 一次最多傳輸多少字節 public static int MAX_CHUNK = 100; public static void sendInfo(String info) { Intent intent = new Intent("main.info"); intent.putExtra("info", info); context.sendBroadcast(intent); } // 讀取二進制信息 public static byte[] readBytes(InputStream inputStream, String log) { byte[] len = new byte[3]; byte[] allbytes = new byte[10000]; int idx = 0; try { inputStream.read(len); // 然后再根據讀取的長度信息讀取二進制流 // 只要不是最后一個二進制流就繼續讀取 while (SocketUtil.parseLen(len) != 0) { byte[] temp = new byte[SocketUtil.parseLen(len)]; inputStream.read(temp); idx = SocketUtil.appendBytes(allbytes, temp, idx); String info = "[" + log + "]接收一個數據包,大小" + SocketUtil.parseLen(len) + "B"; SocketUtil.sendInfo(info); inputStream.read(len); } } catch (IOException e) { e.printStackTrace(); } return SocketUtil.getNewArr(allbytes, idx); } // 將int轉成String public static String intToStr(int len) { StringBuffer sb = new StringBuffer(); if(len < 100) { sb.append("0"); } else if (len < 10) { sb.append("00"); } sb.append(Integer.toString(len)); return sb.toString(); } public static int parseLen(byte[] len) { return Integer.parseInt(new String(len, 0, len.length)); } public static int appendBytes(byte[] arr1, byte[] arr2, int st) { for(int i=st; i<arr2.length; i++) { arr1[i] = arr2[i-st]; } return arr2.length+st; } public static byte[] getNewArr(byte[] arr, int idx) { byte[] newarr = new byte[idx]; for(int i=0; i<idx; i++) { newarr[i] = arr[i]; } return newarr; } }
最后是定義我們的客戶端和服務端
public class SocketClient { private final String HOST = "localhost"; private final int PORT = 50055; private Socket socket = null; private OutputStream outputStream = null; private InputStream inputStream = null; public SocketClient() { conn(); while(socket == null) {} SocketUtil.sendInfo("服務端連接成功..."); try { outputStream = socket.getOutputStream(); } catch (IOException e) { e.printStackTrace(); } } // 連接服務端 private void conn() { new Thread(()->{ try { socket = new Socket(HOST, PORT); inputStream = socket.getInputStream(); while(true) { // 接收服務端消息0 byte[] type = new byte[1]; inputStream.read(type); if (new String(type, 0, 1).equals("1")) { byte[] infobytes = SocketUtil.readBytes(inputStream, "客戶端"); String info = "[客戶端]接收消息:" + new String(infobytes, 0, infobytes.length); SocketUtil.sendInfo(info); SocketUtil.sendInfo("===================================="); } } } catch (IOException e) { e.printStackTrace(); } }).start(); } // 發送文件 public void sendFile(int size) { new Thread(()->{ try { // 表示發送文件 outputStream.write("2".getBytes()); } catch (IOException e) { e.printStackTrace(); } for(int i=0; i<size/SocketUtil.MAX_CHUNK+1; i++) { StringBuffer sb = new StringBuffer(); if (i!=size / SocketUtil.MAX_CHUNK) { for (int j = 0; j < SocketUtil.MAX_CHUNK; j++) { sb.append('a'); } } else if(i==size/SocketUtil.MAX_CHUNK && size%SocketUtil.MAX_CHUNK==0) { break; } else { for (int j = 0; j < size % SocketUtil.MAX_CHUNK; j++) { sb.append('a'); } } try { SocketUtil.sendInfo("[客戶端]發送一個數據包,大小" + sb.toString().getBytes().length + "B"); // 發送chunk的長度 outputStream.write(SocketUtil.intToStr(sb.toString().getBytes().length).getBytes()); // 發送chunk塊 outputStream.write(sb.toString().getBytes()); } catch (IOException e) { e.printStackTrace(); } } // 最后發送000表示結束 try { outputStream.write("000".getBytes()); } catch (IOException e) { e.printStackTrace(); } }).start(); } }
public class SocketServer { private final int PORT = 50055; private ServerSocket serverSocket = null; public SocketServer() { // 啟動服務端監聽 start(); while(serverSocket == null) {} SocketUtil.sendInfo("服務端啟動..."); } // 啟動服務端監聽程序 private void start() { new Thread(()->{ try { serverSocket = new ServerSocket(PORT); Socket socket = serverSocket.accept(); InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream(); while(true) { byte[] type = new byte[1]; inputStream.read(type); String typeinfo = new String(type, 0, 1); if(typeinfo.equals("2")) { byte[] file = SocketUtil.readBytes(inputStream, "服務端"); String filetxt = new String(file, 0, file.length); String info = "[服務端]接收完文件,大小" + file.length + "B" + "\n"; info = info + "[服務端]具體內容如下:" + "\n" + filetxt; SocketUtil.sendInfo(info); // 給客戶端發送一個響應信息表示接收成功 String typetxt = "1"; outputStream.write(typetxt.getBytes()); String successinfo = "文件接收成功"; String lentxt = SocketUtil.intToStr(successinfo.getBytes().length); outputStream.write(lentxt.getBytes()); outputStream.write(successinfo.getBytes()); outputStream.write("000".getBytes()); } } } catch (IOException e) { e.printStackTrace(); } }).start(); } }
上述代碼中,服務端只負責接收二進制流,客戶端只負責發送二進流,并且服務端在接收完二進制流數據后,會給服務端返回一個表示接收成功的文字信息。
到此,相信大家對“Android怎么使用socket進行二進制流數據傳輸”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。