轉自: https://www.cnblogs.com/liqw/p/4867657.html
一、UDP協議全稱是用戶數據報協議 ,在網絡中它與TCP協議一樣用於處理數據包,是一種無連接的協議。
1、UDP是一個無連接協議,傳輸數據之前源端和終端不建立連接;
2、不維護連接狀態,包括收發狀態等,因此一臺服務機可同時向多個客戶機傳輸相同的消息;
3、UDP信息包的標題很短,8個字節,對於TCP的20個字節信息包的額外開銷很小;
4、吞吐量不受擁擠控制算法的調節,只受應用軟件生成數據的速率、傳輸帶寬、源端和終端主機性能的限制;
5、不保證可靠交付;
6、UDP是面向報文的。
二、UDP的代碼編程需要用到DatagramSocket類,Java使用DatagramSocket代表UDP協議的Socket,先了解一下如何使用這個類。
server服務端(接收數據方)創建步驟
1、生成DatagramSocket對象,參數爲端口號
1 | DatagramSocket socket = new DatagramSocket ( 8888 ); |
2、byte數組用來接收數據
1 | byte data[] = new byte [ 1024 ]; |
3、DatagramPackage以包形式裝載byte數組
1 | DatagramPacket packet = new DatagramPacket(data, data.length); |
4、使用DatagramPacket的receive方法接收發送方所發送的數據,是一個阻塞的方法
1 | socket.receive(packet); |
5、接收到的數據轉變化成可讀字符串
1 | String result = new String(packet.getData(), packet.getOffset(), packet.getLength()); |
client客戶端(發送數據方)創建步驟
1、生成DatagramSocket對象,參數爲端口號
1 | DatagramSocket socket = new DatagramSocket ( 8888 ); |
2、創建一個InetAddress對象,用於確定server客戶端(數據接收方),參數爲IP地址,如我的IP地址爲192.168.1.103
1 | InetAddress serverAddress = InetAddress.getByName( "192.168.1.103" ); |
3、需要發送的數據轉化爲byte數組
1 2 | String sendData= "hello word" ; byte data[] = sendData.getBytes(); |
4、生成一個DatagramPacket對象,包含需要發送的byte數組,byte數組長度,已設置IP地址的serverAddress,和服務端一致的端口號(這裏是8888)
1 | DatagramPacket packet = new DatagramPacket(data, data.length, serverAddress, 8888 ); |
5、發送數據,調用DatagramSocket對象的send方法
1 | socket.send(packet); |
三、代碼demo演示
server服務端,可以直接運行在eclipse即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; public class UDPServer { public static void main(String[] args) throws IOException { DatagramSocket socket = null ; try { socket = new DatagramSocket( 8888 ); } catch (Exception e) { e.printStackTrace(); } while ( true ) { byte data[] = new byte [ 1024 ]; DatagramPacket packet = new DatagramPacket(data, data.length); socket.receive(packet); String result = new String(packet.getData(), packet.getOffset(), packet.getLength()); System.out.println( "receive client's data: " + result); } } } |
若多次運行會提示錯誤:Address already in use: Cannot bind,關掉之前開啓的即可。
Android客戶端代碼demo演示,需要注意的是端口號是與服務端一致的,IP地址是服務端的IP地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | import android.app.Activity; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class UDPActivity extends Activity { private Button bt_send_data = null ; DatagramSocket socket = null ; InetAddress serverAddress = null ; @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); bt_send_data = new Button( this ); bt_send_data.setText( "發送" ); setContentView(bt_send_data); try { socket = new DatagramSocket( 8888 ); serverAddress = InetAddress.getByName( "192.168.1.101" ); } catch (Exception e) { e.printStackTrace(); } bt_send_data.setOnClickListener( new OnClickListener() { @Override public void onClick(View arg0) { new Thread( new Runnable() { @Override public void run() { try { String sendData = "hello world" ; byte data[] = sendData.getBytes(); DatagramPacket packet = new DatagramPacket(data, data.length, serverAddress, 8888 ); socket.send(packet); } catch (Exception e) { e.printStackTrace(); } } }).start(); } }); } } |
在AndroidManifest.xml添加權限和註冊
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <?xml version= "1.0" encoding= "utf-8" ?> <manifest xmlns:android= "http://schemas.android.com/apk/res/android" package = "com.libill.demos" android:versionCode= "1" android:versionName= "1.0" > <uses-sdk android:minSdkVersion= "8" android:targetSdkVersion= "10" /> <uses-permission android:name= "android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name= "android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name= "android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name= "android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name= "android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name= "android.permission.INTERNET" /> <application android:allowBackup= "true" android:icon= "@drawable/ic_launcher" android:label= "@string/app_name" android:theme= "@style/AppStartTheme" > <activity android:name= "com.liqw.demos.activity.UDPServerActivity" android:label= "@string/app_name" > <intent-filter> <action android:name= "android.intent.action.MAIN" /> <category android:name= "android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> |
這樣即可跑起demo做測試了。先運行服務端,再點擊發送4次,服務端的log如下: