转自: 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如下: