【UDP demo及抓包分析】

上一篇看完了纯udp的理论介绍。我用个简单的例子测试下。

因为本地wireshark抓包需要特殊设置,所以demo找了边上的电脑测试下

这是client端

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;

public class UDPClient {
	
	 public static void main(String[] args) {  
	 
		 //以 "字节数组" 的形式开辟一块内存用于缓存接收到的UDP数据包  
	        byte[] buffer = new byte[1024];  	          
	        //虽然开辟的缓冲内存大小为1024字节,但也可以设置一个小于该值的缓存空间接收数据包  
	        DatagramPacket rdp = new DatagramPacket(buffer, buffer.length); 
		 
		 
	        DatagramPacket dp = null;  
	        DatagramSocket ds = null;  
	        try {  
	            //new 一个DatagramSocket对象(即打开一个UDP端口准备从此处发出数据包)  
	            ds = new DatagramSocket(9998);
	        }catch (SocketException e) {  
	            e.printStackTrace();  
	        }   
	        System.out.println("client listen on 9998");
	     
		        //将要发送的数据、要发送到什么地址设置好并打成一个 DatagramPacket 包  
		        dp = new DatagramPacket((new String("Hello!"+9)).getBytes(), (new String("Hello!"+9)).getBytes().length, new InetSocketAddress("10.253.8.233", 9999));  
		       
		        try {  		           	         
		            ds.send(dp);  		        
		        } catch (SocketException e) {  
		            e.printStackTrace();  
		        } catch (IOException e) {  
		            e.printStackTrace();  
		        }
		        System.out.println(dp.getData().toString());
	       
	       while(true) {  
	            try {  
	                //receive() 方法是一个阻塞性方法!  
	                ds.receive(rdp);  
	            } catch (IOException e) {  
	                e.printStackTrace();  
	            }  
	            //打印下接收到server返回数据
	            System.out.println("client:"+new String(buffer, 0, rdp.getLength()));  
	       }    
	    }  

}

这是server端

import java.io.IOException;  
import java.net.DatagramPacket;  
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;  
  

public class UDPServer {  
    public static void main(String[] args) {  
          
        //以 "字节数组" 的形式开辟一块内存用于缓存接收到的UDP数据包  
        byte[] buffer = new byte[1024];  
          
        //虽然开辟的缓冲内存大小为1024字节,但也可以设置一个小于该值的缓存空间接收数据包  
        DatagramPacket dp = new DatagramPacket(buffer, buffer.length);  
        
        DatagramSocket ds = null;  
        try {  
            //监听在UDP 9999 端口  
            ds = new DatagramSocket(9999);  
        } catch (SocketException e) {  
            e.printStackTrace();  
        }  
        System.out.println("server listen on 9999");  
        while(true) {  
            try {  
                //receive() 方法是一个阻塞性方法!  
                ds.receive(dp);  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
            //从下一行代码中可以学习到一种用字节数组构造字符串对象的方法  
            System.out.println(new String(buffer, 0, dp.getLength()));  
            String response = "udp receied back."+new String(buffer, 0, dp.getLength());
            DatagramPacket dsp = new DatagramPacket(response.getBytes(),response.length(), new InetSocketAddress("10.253.8.138", 9998)) ; // 所有的信息使用buf保存
            try {
				ds.send(dsp);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        }  
    }  
  
}  
看下日志,客户端的:

client listen on 9998
[B@4aa298b7
client:udp receied back.Hello!9

再看下抓包截图。


可以看出来,client发起udp请求之前,先会在局域网内部发一个广播,根据arp协议从ip获取Mac地址。

而server在回复client的请求的时候,也是先发一个广播获取client的Mac地址。

在看下,抓包的详细报文


我们可以看到图上红框内部的14位是帧头,包含了:目的mac地址,源mac地址,还有上层协议:这里x0800表示IPV4.

***************************************************************************************************************************************

再看45开头的是IP头,逐位看:


45C0:4代表ipv4协议,5代表IP首部的长度(指代首部占32bit/4byte的数目),20字节.C0代表区分服务领域:表示cs6。具体参见百科解释:https://baike.baidu.com/item/DSCP/1781510

0023:(包含报头和数据)总长度35

41bb:16位标志

0000: 3位标志加13位片偏移

c811: C8代表生存时间timetolive 200,11表示8位协议17,代表UDP。

0000:代表首部校验和

0afd088a:代表了32位源IP值10.253.8.138

0afd08e9:代表了32位目的IP值10.253.8.233

没有选项数据,接下来是数据,也是UDP的头部:

*****************************************************


270e:表示16位源端口9998

270f:表示16位目的端口9999

000f:表示udp数据报长度:15(因为udp长度固定位8字节,所以数据长度应该为15-8=7字节)

278d:表示16位校验和

48656c6c6f2139:为数据,转换后为“hello!9”.正好是7个字节

返回的报文跟上面发出的类似,只贴个截图,不再一一标注。



  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值