udp協議(用戶數據報協議)是一種不可靠的網絡協議,它在通信實例的兩端各建立一個socket,但是這兩個socket之間并沒有虛擬鏈路,這兩個socket只是發送,接收數據報的對象。
udp的優缺點:
1. 因為udp協議是面向非連接的協議,沒有建立連接的過程,因此它的通信效率很高。很適合一些即時性很強的應用場景。
2.因為在正式通信前不必與對方先連接,不管對方狀態就直接發送,至于對方是否可以收到這些數據內容,udp無法控制,所以說udp是一種不可靠的協議。
3.傳輸大小限制在64kb以下,這個尤其要注意,在做這個實例的時候,因為沒有考慮到這個,直接傳了一張大圖,結果找了半天的原因。
java使用datagramsocket代表udp協議的socket,它唯一的作用是接收和發送數據報,至于數據究竟發給誰,datagramsocket并不清楚;具體發送的目的地是由datagrampacket自身決定。當client/server程序使用udp協議時,實際上并沒有嚴格的服務器和客戶端的區分。通常固定ip地址,固定端口的datagramsocket對象所在程序被稱為服務器,因為有固定的ip,端口地址,其他客戶端的數據報可以直接發送到服務器上。
接收數據的datagrampacket在實例化時無需指定端口和ip地址,給出數據數據的字節數組以及長度即可。然后調用datagramsocket的receive()方法等待數據報的到來,該方法阻塞線程直到受到一個數據報為止。
發送數據的datagrampacket不同的是,需要給出完整的目的地,包括ip地址和端口,這樣數據報才能知道將數據發給誰。當服務器接收到一個datagrampacket對象后,如果想向該數據報的發送者反饋一些消息,但由于udp協議是面向非連接的,所以不知道數據報是誰發送過來的,但程序可以調用datagrampacket的getaddress()(返回一個inetaddress對象,發報的ip地址),getport()(返回發報的端口)和getsocketaddress()(返回一個socketaddress對象,該對象可以同時代表ip地址和端口)。
實現思路:每個客戶端啟動時都會向服務端發送一個字符串,該字符串代表該客戶端已經上線,并在服務端將每個客戶端的發報地址(即socketaddress對象)保存在一個set集合中。當點擊任意一個上線的客戶端的發送圖片按鈕,該圖片數據就會被發送到服務端上,服務端遍歷socketaddress集合,并將圖片數據轉發到每個socketaddress對應的客戶端上,就實現了簡單的圖片群發。具體代碼如下:
客戶端發送數據報的工具類:
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
public class datagramutil { public static final int boadcast_port = 8888 ; public static final string dest_ip = "192.168.1.101" ; private static final int data_len = 50000 ; //定義本程序私聊的socket實例 private datagramsocket singlesocket = null ; //定義接收網絡數據的字符數組 byte [] inbuff = new byte [data_len]; private handler handler; //構造器,初始化資源 public datagramutil(handler handler) throws exception { this .handler = handler; //創建用于私聊的datagramsocket對象 singlesocket = new datagramsocket(); new readsingle().start(); } //定義單獨用戶發送消息的方法 public void sendsingle( byte [] msg) { try { datagrampacket packet = new datagrampacket( new byte [ 0 ] , 0 , inetaddress.getbyname(dest_ip) , boadcast_port); packet.setdata(msg); singlesocket.send(packet); } catch (ioexception e) { e.printstacktrace(); } } //不斷地從datagramsocket中讀取數據的線程 class readsingle extends thread { byte [] singlebuff = new byte [data_len]; private datagrampacket singlepacket = new datagrampacket(singlebuff , singlebuff.length); @override public void run() { while ( true ) { // 讀取socket中的數據 try { //讀取socket中的數據 singlesocket.receive(singlepacket); //處理得到的消息 message msg = new message(); msg.what = 0x123 ; msg.obj = singlebuff; handler.sendmessage(msg); } catch (ioexception e) { e.printstacktrace(); if (singlesocket != null ) { //關閉該socket對象 singlesocket.close(); } } } } } } |
收到服務端發來的圖片數據時,使用handler更新ui。
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
public class mainactivity extends activity { private button button; private imageview img; private datagramutil datagramutil; handler handler = new handler() { @override public void handlemessage(message msg) { if (msg.what == 0x123 ) { byte [] result = ( byte []) msg.obj; img.setimagebitmap(bitmapfactory.decodebytearray(result , 0 , result.length)); } } }; @override protected void oncreate(bundle savedinstancestate) { super .oncreate(savedinstancestate); setcontentview(r.layout.main_activity); button = (button) findviewbyid(r.id.send_img_all); img = (imageview) findviewbyid(r.id.receiver_img); try { datagramutil = new datagramutil(handler); senddata(stringyobyte()); } catch (exception e) { e.printstacktrace(); } button.setonclicklistener( new view.onclicklistener() { @override public void onclick(view view) { senddata(bitmaptobyte()); } }); } private void senddata( final byte [] msg) { new thread() { @override public void run() { datagramutil.sendsingle(msg); } }.start(); } public byte [] bitmaptobyte() { bitmap bitmap = bitmapfactory.decoderesource(getresources() , r.drawable.wenqing); bytearrayoutputstream bytearray = new bytearrayoutputstream(); bitmap.compress(bitmap.compressformat.png , 100 , bytearray); bitmap.recycle(); return bytearray.tobytearray(); } public byte [] stringyobyte() { string loginstr = "hello" ; return loginstr.getbytes(); } } |
服務端代碼(運行該java程序即可):
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
|
public class udpserver { public static final int port = 8888 ; private static final int data_len = 50000 ; byte [] inbuff = new byte [data_len]; private datagrampacket inpacket = new datagrampacket(inbuff , inbuff.length); private datagrampacket outpacket; private datagramsocket serversocket; private set<socketaddress> socketaddresslist = collections.synchronizedset( new hashset<socketaddress>()); public void init() throws ioexception { serversocket = new datagramsocket(port); while ( true ) { serversocket.receive(inpacket); string result = new string(inbuff , 0 , inbuff.length); if (result.trim().equals( "hello" )) { socketaddresslist.add(inpacket.getsocketaddress()); } else { for (iterator<socketaddress> iterator = socketaddresslist.iterator(); iterator.hasnext() ; ) { socketaddress socketaddress = iterator.next(); outpacket = new datagrampacket(inbuff , inbuff.length , socketaddress); serversocket.send(outpacket); } } } } public static void main(string[] args) throws ioexception { new udpserver().init(); } } |
這樣實現了簡單的圖片群發的效果。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/qq_33022345/article/details/53448103