日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

android 判断byte值_Android开发之UDP可靠性传输

發布時間:2024/4/18 Android 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android 判断byte值_Android开发之UDP可靠性传输 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

軒羽:Android開發之UDP?zhuanlan.zhihu.com

在這一篇文章里,小編說到UDP是不可靠的,故,我們要自己寫一套協議,來使UDP實現可靠性傳輸,這里,小編和小編的小伙伴一起,寫了一個協議,實現了通過UDP來傳輸文件,下面就來和大家講講我們的思路和具體實現


在最開始的時候,我和我的伙伴想了許多的UDP協議,剛開始的時候想的特別復雜,好在,后來有位非常優秀的學長,跟我們提出了許多寶貴的建議,給我們提供了很多思路,這樣,我們在后面所涉及的UDP可靠性傳輸才有了一個較為完全的方案。

以下便是我們的大致方案:

1.數據包的規定:

我們知道,在Android中要實現通信,需要DatagramPacket類

而且,在后面,會有不同類型的包,同時考慮服務器接收多方發的文件的情況,所以我們對DatagramPacket類中的字節數組做如下規定:

(1)在數據包開始和結束處,分別用$和@來做標記符,以此來處理網絡擁擠情況而產生的分包問題

(2)type:用一個字節來做包類型判斷,因為在整個文件的傳輸過程中,我們有三個環節,每個環節所用的包是不相同的,故對其進行分類,以示區分

(3)包的序號:這部分我們采用了四個字節,通過這四個字節,我們將其轉換成int類型。因為在對文件進行分包的時候,必定會將文件的字節數組分成不同的包,為了讓接收端能正確地將接收到的包進行整理,故對每一個包都進行序號排序

(4)預留處:這個當初是學長的建議,因為在實際的商業應用中,會存在文件的狀態等考慮,故先預留一些字節,以實現數據包的擴展性。而在我們編寫的UDP協議中,我們用其中的第一個字節來便是文件編號(考慮到多個發送端向服務器同時傳輸文件的情況)

(5)文件內容:這里是用1014個字節來對文件進行分包

2.建立連接

在傳輸文件開始時,我們采用了TCP中的三次握手來建立連接

其中,我們規定Server的序號為5,而client的序號為隨機生成,然后通過如圖方式,進行握手。當然,在client向服務器進行第一次握手的時候,可能會造成丟包的情況,所以,在client出,會有一個重傳機制。同樣的,在進行第二次握手時,也需在Server中進行重傳。如何重傳,小編后面會講到。在后面所講的傳輸過程,均需要考慮重傳。

當然了,這是傳文件過程中的第一次傳輸,所以需對包進行分類,我們規定,建立連接時所用包的類型(type)為0。

而seq和ack這兩個部分,我們在這里分別用一個字節來表示,其中均屬于數據包中的文件內容部分

3.傳輸文件信息

當Server和client建立好連接之后,client首先需要向Server傳輸文件對應的信息,這樣才好讓Server對該文件創建空間

在第三次握手之后,client會將文件信息,轉換成對應的字節數組,并放置于數據包中的文件內容部分,傳給Server。

Server在接收到這個數據包之后,會解析其中的文件信息,然后生成對應的文件對象空間,來儲存即將發過來的文件。并且Server會生成一個文件序號,放置于數據包中預留處部分。之后Server就會將該應答包返回給client

在這其中要考慮到重傳,同時,這其中所用到的數據包類型(type),我們規定為1。

當然,文件信息不止小編所列的這些,還會有許多,應視情況而定,文件信息的放置方式有許多,可有設計者來定。在這里,小編和小伙伴是這樣規定的:

4.文件具體內容傳輸

4.1 在進行文件信息傳輸成功后,就會開始進行文件內容的傳輸

(1)首先,client先將文件轉換成字節數組,然后用1014個字節來對文件進行分包

(2)在分包之后,在類,在類型type(這里我們規定為2),包的序號,預留處中的文件編號處寫好對應的信息,然后把文件內容寫好,之后,將其發送給Server

(3)Server在接收到這個包之后,會發送一個類型3的數據包,同時也包含了文件編號,包的序號的信息,以告知client:不用再重發,Server已經接收到了

(4)當client傳輸完所有的包,并且均收到Server所有對應的應答包之后,就會發送一個類型4的數據包,其中附有文件編號,已告知Server:client已傳完所有的數據包了。Server在接收到這個包之后,就會對包進行整合,生成對應的文件

在這其中會涉及到重傳機制

4.2 重傳機制:

(1)在這里 小編先建立一個類,暫且稱作user類,其中包括:包序號、發送次數、上次發送時間、1024字節數組三個屬性。

(2)小編用HashMap來進行存儲這個類的對象,其中包的序號作為 key,user對象作為value

(3)在對文件進行分包之后,就對每一個數據包創建一個user對象,并完善其中的信息,添加至HashMap中;在收到對應的應答包之后,就remove HashMap中對應的user對象

(4)新開一個線程,不斷地循環,并判斷是否需要重發:若當前發送時間距上次發送時間相差超過3000ms,則重發。當發現HashMap中已經沒有存儲對象時,則開始發送數據類型為4的 數據 包 ,并終止線程

5.文件編碼

Server接收到類型為4的數據包之后,就開始通過文件名,合并每個數據包中的,文件內容部分的字節,然后通過文件 IO流生成對應的文件


當然了,在這里小編和小伙伴們也只是實現了把文件從手機端傳送到了電腦端,而之后從電腦端傳輸文件到手機端這一環節,小編和小伙伴雖然寫了,但是由于時間等原因,還沒來得及演示,所以現在還只能說跟大家分享這些,之后,小編把后面部分完成了就會跟大家分享的。

以下便是小編負責Server部分,這部分只包含從client傳文件到Server的過程

1.UDPserver代碼:

package Server; import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream; import java.io.IOException; import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;import java.net.SocketException;import java.util.HashMap; import Client.SendThread;import Client.UserSend;/ * 基站類,用于處理發過來的1024的包 / public class UDPserver { // 服務器端口號 private int port = 9999; // 服務器序號,用于三次握手 private String no = "5"; int no1 = 5; // 服務器IP地址 String serverIP = "";// 目標地址 InetAddress destaddress = null; int destport = 8888; // 接收通道 DatagramSocket socket = null; // 接收包 DatagramPacket request = null; // 接收的字節數組 byte[] msg = null;// 文件隊列,采用HashMap方法,總共有255個 HashMap<Integer, User> filemap = new HashMap<Integer, User>();// 緩存區隊列 bufferstorage[] bstorage = new bufferstorage[255];// 得到發過來的包 private void getPackage(byte[] msg, DatagramPacket request,DatagramSocket socket) throws Exception {// TODO Auto-generated method stubthis.msg = msg;this.request = request;this.socket = socket;destaddress = request.getAddress();//destport = request.getPort();//System.out.println("destaddress="+destaddress);System.out.println("開始對包進行類別判斷");// 對包進行類別判斷Adjusttype();}// 字節數組類型判斷 private void Adjusttype() throws Exception {// TODO Auto-generated method stub// 獲取類型的字節byte[] b = new byte[1];System.arraycopy(msg, 1, b, 0, 1);//System.out.println(msg);// 轉換成對應字符串String type = b[0]+"";//new String(b);System.out.println("包的類型type=" + type);// 不同類型對應不同的處理方式if ("0".equals(type)) {solve0();}if ("1".equals(type)) {solve1();}if ("2".equals(type)) {solve2();}if ("3".equals(type)) {}if ("4".equals(type)) {solve4();}}// 分配文件序號 private int getfileno() {// TODO Auto-generated method stubint i = 0;for (; i < 255; i++) {if (filemap.get(i) == null)break;}return i; }/*** 把一個int數值轉為6個字節* * @param i* @return*/ public static byte[] intTo5Byte(int i) {byte[] result = new byte[5];result[0] = (byte) ((i >> 32) & 0xFF);result[1] = (byte) ((i >> 24) & 0xFF);result[2] = (byte) ((i >> 16) & 0xFF);result[3] = (byte) ((i >> 8) & 0xFF);result[4] = (byte) (i & 0xFF);return result; }/*** 把一個int數值轉為4個字節* * @param i* @return*/ public static byte[] intTo4Byte(int i) {byte[] result = new byte[4];result[0] = (byte) ((i >> 24) & 0xFF);result[1] = (byte) ((i >> 16) & 0xFF);result[2] = (byte) ((i >> 8) & 0xFF);result[3] = (byte) (i & 0xFF);return result;}/*** 把字符串的每個字符轉化為兩個字節 返回一個字節數組* * @param str* @return*/ public static byte[] get2Byte(String str) throws Exception {int length = 0;// 字節數組的長度byte[] buffer1 = new byte[1024];for (int i = 0; i < str.length(); i++) {char a = str.charAt(i);byte[] bu = new byte[2];if (a < 256) { // 英文字符bu[0] = 0;bu[1] = (byte) a;} else { // 中文字符bu = (a + "").getBytes("GBK");}buffer1[length++] = bu[0];buffer1[length++] = bu[1];}byte[] buffer2 = new byte[length];System.arraycopy(buffer1, 0, buffer2, 0, length);return buffer2; }/*** 把輸入的字節數組還原為字符串的方法(每兩位還原為一個字符)* * @return*/ public static String getString(byte[] buffer) throws Exception {String str = "";for (int i = 0; i < buffer.length; i += 2) {byte[] bu = new byte[2];bu[0] = buffer[i];bu[1] = buffer[i + 1];if (bu[0] == 0) { // 高位為0,是英文字符char a = (char) bu[1];str += a;}if (bu[0] != 0) {String a = new String(bu, "GBK");str += a;}}return str; }/*** 把一個int數值轉化為2個字節* * @param num* @return*/ public static byte[] intTo2Byte(int num) {byte[] twoByte = new byte[2];if (num > 255) {twoByte[0] = (byte) (num / 256);twoByte[1] = (byte) (num - (num / 256) * 256);} else {twoByte[0] = 0;twoByte[1] = (byte) num;}return twoByte; }// 4個字節轉換成int public static int byteArray2Int(byte[] b) {int num = b[3] & 0xFF;num |= ((b[2] << 8) & 0xFF00);num |= ((b[1] << 16) & 0xFF0000);num |= ((b[0] << 24) & 0xFF0000);return num;}// 兩個字節轉換成int類型 public static int tBytesToint(byte[] b) {// int a =(((int) b[0]) << 8) + b[1];// if (a < 0) {// a = a + 256;// }// return a;int num = b[1] & 0xFF;num |= ((b[0] << 8) & 0xFF00);// num |=((b[1] <<16)& 0xFF0000);// num |=((b[0] <<24)& 0xFF0000);return num;}// 6ge字節轉換成int類型 public static int sBytesToint(byte[] b) {int num = b[5] & 0xFF;num |= ((b[4] << 8) & 0xFF00);num |= ((b[3] << 16) & 0xFF0000);num |= ((b[2] << 24) & 0xFF0000);num |= ((b[1] << 32) & 0xFF0000);num |= ((b[0] << 40) & 0xFF0000);return num;}// 三次握手的處理方式 public void solve0() throws IOException {// 存儲對應的整數信息int flag = 0;String s = "";// 獲取ack的字節,并轉出成字符串byte[] b = new byte[1];System.arraycopy(msg, 1022, b, 0, 1);flag = b[0];//flag = Integer.valueOf(ack).intValue();// 第三次握手的情況if (flag == no1 + 1) {// 獲取對應的文件序號b = new byte[1];System.arraycopy(msg, 6, b, 0, 1);int bnno = b[0];//int bnno = Integer.valueOf(bno).intValue();// 把之前的緩存區數組中的信息消除,與第一次握手判斷重發的存儲地方消除this.bstorage[bnno] = null;System.out.println("第三次握手:fileno=" + bnno);}// 第一次握手的情況else {// 判斷是否為重發的消息// 獲取seq的字節,并轉化成數字b = new byte[1];System.arraycopy(msg, 1021, b, 0, 1);int se = b[0];//new String(b);//int se = Integer.valueOf(seq).intValue();System.out.println("seq+++++++++++++++++++++++++===="+se);se++;msg[1022] = (byte)se;msg[1021] = (byte)no1;// 生成一個文件對象,同時存入文件隊列中//User user = new User();// 分配文件的序號int fileno = getfileno();//user.fileno = fileno;//filemap.put(fileno, user);msg[6]=(byte)fileno;// 發送給手機端消息request = new DatagramPacket(msg, msg.length, destaddress, destport);socket.send(request);// 將此消息保存,以便未收到消息時,再次發送bufferstorage bs = new bufferstorage();bs.sendtime = System.currentTimeMillis();bs.destaddress = this.destaddress;bs.destport = this.destport;bs.socket = this.socket;System.arraycopy(msg, 0, bs.msg, 0, msg.length);this.bstorage[fileno] = bs;System.out.println("第一次握手:seq=" + (se - 1) + ";fileno=" + fileno);}}// 得到文件信息 public void solve1() throws Exception {/** 分解包的信息內容*/// 得到文件序號byte[] b = new byte[1];System.arraycopy(msg, 6, b, 0, b.length);int fno = b[0]; // 獲取文件序號User user = new User();//filemap.get(fno);// 獲取補零數b = new byte[2];System.arraycopy(msg, 1021, b, 0, b.length);int num0 = tBytesToint(b);// 獲取文件總字節數b = new byte[6];System.arraycopy(msg, 1015, b, 0, b.length);int bytenum = sBytesToint(b);// 獲取文件包數b = new byte[4];System.arraycopy(msg, 1011, b, 0, b.length);int packnum = byteArray2Int(b);// 獲取文件名b = new byte[1];System.arraycopy(msg, 1010, b, 0, b.length);int num = b[0];b = new byte[num];System.arraycopy(msg, 1010 - num, b, 0, b.length);String filename = getString(b);user.get(filename, packnum, bytenum, num0, fno);filemap.remove(fno);filemap.put(fno, user);// 返回同樣的包request = new DatagramPacket(msg, msg.length, destaddress, destport);socket.send(request);// 將該包放入緩存區bstorage中,以便判斷是否重發bufferstorage bs = new bufferstorage();bs.sendtime = System.currentTimeMillis();System.arraycopy(msg, 0, bs.msg, 0, msg.length);this.bstorage[fno] = bs;bs.destaddress = this.destaddress;bs.destport = this.destport;bs.socket = this.socket;System.out.println("獲取到文件信息:fno=" + fno + "num0=" + num0 + "bytenum="+ bytenum + "packnum=" + packnum + "filename=" + filename+"總字節數="+num);}// 得到文件內容 public void solve2() throws IOException {// 得到當前包的序號byte[] b = new byte[4];System.arraycopy(msg, 2, b, 0, b.length); // 獲取包序號的字節數組int pno = byteArray2Int(b); // 包序號pno// 得到文件序號b = new byte[1];System.arraycopy(msg, 6, b, 0, b.length);//String s = new String(b);int fno = b[0]; // 獲取文件序號System.out.println("獲取到當前包序號:" + pno+";fno="+fno);// 將solve1()中放入緩存區的包給消除this.bstorage[fno] = null;// 將對應的文件序號user中flist中的對應字節數組復制User user = filemap.get(fno);System.out.println("類型2的user"+user.toString());System.out.println("類型2的user.filename:"+user.filename);System.out.println("類型2的user.fileno:"+user.fileno);//System.out.println("msg:"+msg.toString()+";");// fcontent f= new fcontent(); // user.filelist[pno-1] =f; //System.out.println("user.filelist[pno-1].b:"+user.filelist[pno-1].b.toString()+";");System.arraycopy(msg, 8, user.filelist[pno-1].b, 0, user.filelist[pno-1].b.length);// 返回給手機端消息:服務器已收到該消息b = new byte[1];b[0] =3; //"3".getBytes();System.arraycopy(b, 0, msg, 1, b.length);request = new DatagramPacket(msg, msg.length, destaddress, destport);socket.send(request);}// 得到客戶端的消息:所有包已發完,則開始編碼文件 public void solve4() throws IOException {// 得到文件序號byte[] b = new byte[1];System.arraycopy(msg, 6, b, 0, b.length);//String s = new String(b);int fno = b[0]; // 獲取文件序號System.out.println("類型4的文件編號:"+fno);// 將對應的文件序號user中flist中的對應字節數組復制User user = filemap.get(fno);System.out.println("類型4的user.filename:"+user.filename);//System.out.println("user.getfilebyte():"+user.getfilebyte().toString());user.getfilebyte();//byte[] filebyte = user.filebyte;// 將字節數組轉換成對應的文件File f = new File("D:" + user.filename);FileOutputStream fileostr = new FileOutputStream(f);fileostr.write(user.filebyte);System.out.println("已生成對應的文件");// 消除filemap中該文件的信息//filemap.remove(fno);fileostr.flush();fileostr.close();//開始傳輸文件給傳輸對象SendThread sendthread = new SendThread(destaddress, user.filename, "D:");sendthread.start();}public static void main(String[] args) throws Exception {// 接收基站final UDPserver Server = new UDPserver();// 服務器端口號int port = 9999;// 接收通道DatagramSocket socket = null;// 三次握手所要字節數組byte[] msg = new byte[1024];// 接收包DatagramPacket request = null;System.out.println("Sever begins to contact");// 創建對應的通道和傳送包try {socket = new DatagramSocket(port);} catch (SocketException e) {// TODO Auto-generated catch blocke.printStackTrace();}request = new DatagramPacket(msg, msg.length);// 開啟刷新緩存區的線程new Thread() {public void run() {int i = 0;bufferstorage bs;while (true) {i = i % 255;long time = System.currentTimeMillis();bs = Server.bstorage[i];try {Thread.sleep(30);} catch (InterruptedException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}if (bs != null && (time - bs.sendtime) > 3000) {Server.request = new DatagramPacket(bs.msg,bs.msg.length, bs.destaddress, bs.destport);try {bs.socket.send(Server.request);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("重發包一次");Server.bstorage[i].sendtime = System.currentTimeMillis();}i++;}}}.start();System.out.println("刷新緩存區的線程開啟");// 開啟接收while (true) {System.out.println("在接收消息中");try {socket.receive(request);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("接收到消息,進入基站");// 接收到后,進入基站Server.getPackage(msg, request, socket);// 開啟三次握手線程// UDPserver Server = new UDPserver(socket , request.getAddress());// Server.start();}} }

2.User部分

package Server;import java.util.ArrayList;public class User {//文件名String filename = null;//包個數int packnum;//文件總字節數int bytenum;//補零數int num0;//文件序號int fileno;//文件內容字節數組fcontent[] filelist ;//ArrayList<fcontent> filelist = new ArrayList<fcontent>();//文件總字節數組byte[] filebyte;//文件傳輸對象//得到相應信息public void get(String filename, int packnum, int bytenum, int num0, int fileno) {this.filename = filename;this.packnum = packnum;this.bytenum = bytenum;this.num0 = num0;this.fileno = fileno;filelist = new fcontent[packnum];for(int i = 0; i<packnum ; i++){fcontent f= new fcontent();filelist[i] =f;}filebyte = new byte[bytenum];}//得到文件的總字節數組public void getfilebyte() {// TODO Auto-generated method stubint j = 0,i = 0;for( i = 0;i<packnum-1;i++){System.arraycopy(filelist[i].b, 0, filebyte, j*1014, filelist[i].b.length);j++;}System.arraycopy(filelist[i].b, 0, filebyte, j*1014, filelist[i].b.length-num0);} }

3.bufferstorage代碼部分

package Server; import java.net.DatagramSocket; import java.net.InetAddress; public class bufferstorage { public byte[] msg = new byte[1024];//上次發送時間 public long sendtime = 0;//對應的IP地址和port端口 // 目標地址 public InetAddress destaddress = null; public int destport = 0; // 接收通道 public DatagramSocket socket = null; }

4.fcontent代碼部分

Package Server;/** 文件包字節數組*/ public class fcontent {public byte[] b = new byte[1014];}

總結

以上是生活随笔為你收集整理的android 判断byte值_Android开发之UDP可靠性传输的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。