国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

通過UDP建立TCP連接

2019-11-15 00:11:07
字體:
來源:轉載
供稿:網友
通過UDP建立TCP連接解釋
通過UDP廣播查詢服務器的ip地址,然后再建立TCP點對點連接。
應用場景
在服務器IP未知時,并且已知服務器與客戶端明確在一個局域網或者允許組播的子網下。通過UDP發現服務器地址然后再進行TCP連接。(PS:萬維網很多路由器對組播進行了限制,所以不能通過UDP報文在萬維網上進行服務器查詢)
主要問題
Android真機和模擬器對組播處理不同Android不同系統版本對組播處理不同不同網絡對組播有限制,如部分路由網絡限制UDP報文
簡單實現
傳統組播方式,通過255.255.255.255地址全轉發??蛻舳耸盏綀笪暮筮M行相應check,然后通過UDP報文數據獲取服務器的IP地址。然后通過IP地址連接。PS:會有點問題、比如在Android 5.0.1真機(鄙人的手機)上無法接收255.255.255.255組播報文。也有可能是被路由器過濾掉了,但是在模擬器上一切正常。后續給出真機上的解決方案
服務器廣播Hello報文代碼:
 1 PRivate class BoadrcastDispense implements Runnable { 2  3         @Override 4         public void run() { 5             try { 6                 if (UDPSocket == null) { 7                     UDPSocket = new DatagramSocket(udpPortServer); 8                 } 9             } catch (SocketException e1) {10             }11             while (!UDPSocket.isClosed() && flag) {12                 try {13                     Thread.sleep(1000);14                 } catch (InterruptedException e) {15                     e.printStackTrace();16                 }17                 try {18                     // send message19                     String str = "Hello Client";20                     byte backData[] = str.getBytes();21                     DatagramPacket backPacket = new DatagramPacket(backData,22                             backData.length,23                             InetAddress.getByName("255.255.255.255"),24                             udpPortClient);25                     UDPSocket.send(backPacket);26                 } catch (SocketException e) {27                     e.printStackTrace();28                 } catch (IOException e) {29                     e.printStackTrace();30                 }31             }32         }33 34     }

客戶端接收Hello報文代碼
 1 public static boolean searchServer() { 2         try { 3             // receive packet 4             if (udpSocket == null) { 5                 udpSocket = new DatagramSocket(udpPortClient); 6                 udpSocket.setSoTimeout(5000); 7             } 8             byte receiveData[] = new byte[bufferSize]; 9             DatagramPacket receivePacket = new DatagramPacket(receiveData,10                     receiveData.length);11             udpSocket.receive(receivePacket);12             String recieveStr = new String(receivePacket.getData(),13                     receivePacket.getOffset(), receivePacket.getLength());14             System.out.println("服務器IP地址:"15                     + receivePacket.getAddress().getHostAddress());16             System.out.println("接收到服務器反饋:" + recieveStr);17             if (recieveStr.equalsIgnoreCase("Hello Client")) {18                 serverIP = receivePacket.getAddress().getHostAddress();19                 System.out.println("連接到服務器成功");20                 return true;21             }22         } catch (SocketException e) {23             e.printStackTrace();24         } catch (UnknownHostException e) {25             e.printStackTrace();26         } catch (IOException e) {27             e.printStackTrace();28         }29         System.out.println("連接到服務器失敗");30         return false;31 32     }
在模擬器上進行調試時,上面代碼就已經足夠了。但是在真機上運行時,發現一直阻塞在receive那里。各種 百度 + Google ,依然無果,并且發現很多人都遇到過這個問題。有三個可能的原因:
  1. 省電???

    Android部分機型為了省電,關閉了wlan的組播功能,但是可以通過代碼開啟。

1 WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);2 WifiManager.MulticastLock lock = manager.createMulticastLock("test wifi");3 lock.acquire();4 // 要執行的組播操作,如receive等5 lock.release();

但經過嘗試,并非這個原因導致。

2.路由or網絡設備屏蔽掉了255報文

WIFI網絡屏蔽掉了255.255.255.255的組播報文但是通過反向發送255報文(Android向PC發,發現PC可以收到)可以成功。所以排除了這個原因。PS:這個原因在其他地方還是很有可能的,很多路由器為了防止廣播風暴,都默認屏蔽了255組播,或者限制了組播數量。比如華為的設備默認限制為30%,丟包率可想而知

3.子網域無法向外發送廣播

這個就比較理論化了。說的是家里的路由器的IP地址是192.168.0.1的地址,而192.168.x.x屬于內網域,無法向外廣播啥的....計算機網絡沒學好,暫時不考慮這個原因
改進實現
由于各種搜索無果,決定換一種思路嘗試,受到在嘗試過程中可以通過Android向PC發送255廣播報文的其他,想到了以下兩種解決方案 1. 利用Android建立服務器,讓PC反向連接到Android 優點是可以簡單快速的建立P2P連接,但是僅限于P2P連接,如果想讓服務器接入多個客戶端,該方法不適用 2. 先通過PC獲取Android的IP地址,然后發定點UDP報文,再從定點UDP報文獲取服務器IP 優點是還是基本的PC做server,android做client的結構,只是要多一步IP中轉 至于我的方法,由于服務器的代碼基本寫完了,不想做大的更改,所以采用的第二種方法,代碼還是比較簡單:
通過Android端向PC端發送255報文
 1     public static void sendPacktToServer() { 2         try { 3             // receive packet 4             if (udpSocket == null) { 5                 udpSocket = new DatagramSocket(udpPortClient); 6                 udpSocket.setSoTimeout(5000); 7             } 8             String str = "Hello Server"; 9             byte[] data = str.getBytes();10             DatagramPacket sendPacket = new DatagramPacket(data,11                     data.length,12                     InetAddress.getByName("255.255.255.255"), udpPortServer);13             lock.acquire();14             udpSocket.send(sendPacket);15             lock.release();16         } catch (SocketException e) {17             e.printStackTrace();18         } catch (UnknownHostException e) {19             e.printStackTrace();20         } catch (IOException e) {21             e.printStackTrace();22         }23     }

PC端接收到Android發送的255報文后直接回饋定向UDP報文,這樣Android端就可以收到該報文了,然后再建立TCP連接
 1    private class BoardcastListener implements Runnable { 2  3         @Override 4         public void run() { 5             try { 6                 if (UDPSocket == null) { 7                     UDPSocket = new DatagramSocket(udpPortServer); 8                 } 9             } catch (SocketException e1) {10             }11             while (!UDPSocket.isClosed() && flag) {12                 try {13                     // receive message14                     byte[] recvBuf = new byte[bufferSize];15                     DatagramPacket recvPacket = new DatagramPacket(recvBuf,16                             recvBuf.length);17                     UDPSocket.receive(recvPacket);18                     String recvStr = new String(recvPacket.getData(), 0,19                             recvPacket.getLength());20                     ServerFrame.getInstance().appendServerStr(21                             "接收到UDP消息: " + recvStr + " 來自:"22                                     + recvPacket.getAddress().getHostAddress());23                     // send back message24                     String str = "Hello Client";25                     byte backData[] = str.getBytes();26                     DatagramPacket backPacket = new DatagramPacket(backData,27                             backData.length, recvPacket.getAddress(),28                             udpPortClient);29                     UDPSocket.send(backPacket);30                 } catch (SocketException e) {31                     e.printStackTrace();32                 } catch (IOException e) {33                     e.printStackTrace();34                 }35             }36         }37 38     }

至此,基本的核心代碼就全貼出來了,目前經過測試在模擬器上和android真機上均可以連接到服務器
總結
其實主要用途還是局域網內在不知道對方IP情況下怎么建立連接的一種手段,解決方案其實有很多。比如全通過UDP交互等,但是考慮到TCP不需要手動維護穩定性,所以還是偏好使用TCP連接進行數據傳輸。(能夠使用場景:局域網游戲、物聯網相互連接啥的)誠然,也可以手動查詢IP地址,然后輸入IP地址進行TCP連接。但是在移動設備上大家還是比較喜歡一鍵式的東西,通過UDP進行服務器自動發現,這個功能還是有那么一點點用處。。。。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 和静县| 日喀则市| 汉阴县| 永德县| 尼勒克县| 沧州市| 营口市| 瑞丽市| 离岛区| 梁河县| 平罗县| 剑川县| 图们市| 伊宁市| 宁阳县| 汉寿县| 西藏| 泊头市| 大新县| 纳雍县| 宽甸| 扎兰屯市| 莆田市| 民乐县| 牡丹江市| 济源市| 云浮市| 荣成市| 莫力| 宿迁市| 清远市| 固镇县| 临邑县| 新龙县| 冕宁县| 信宜市| 怀柔区| 高邑县| 上饶县| 微山县| 徐汇区|