【UDP demo及抓包分析】

来源:互联网 发布:js实现图片预加载动画 编辑:程序博客网 时间:2024/05/29 23:22

上一篇看完了纯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 blocke.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个字节

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