udp协议分析实验报告怎么做(计算机网络udp实验报告)
实验报告怎么写
实验报告的写法如下:
一、完整实验报告的书写
完整的一份实验报告一般包括以下项目:实验名称:
实验目的:
实验器材:
实验原理:
实验步骤:
实验数据记录(表格)及处理:
实验结论(结果推导):
实验讨论或分析等。
二、实验报告书写方法
1、实验名称:就是这个实验是做什么的。
2、实验目的:一般都写掌握什么方法啊;了解什么啊;知道什么啊;会什么啊;……等。
3、实验器材:就是做这个实验需要的所有器材(仪器)。
4、实验原理:就是这个实验是根据什么来做的,一般书上会写,抄一下也就可以啦。
5、实验步骤:就是你做实验的过程,开始操作时,(1)做什么;(2)做什么;(3)做什么;……
6、实验数据记录(表格)及处理:根据实验中涉及以及实验得到的数据,设计表格,将有关数据填在表格相应的位置;数据处理,就是该计算的,按要求计算后填入表格对应位置。
7、实验结论(结果推导):就是做这个实验要得到的结果。
8、分析于讨论:写你的实验结果是否适合真实值?如果有误差要分析产生误差的原因,还有实验的一些比较关键的步骤的注意事项等。
对于初中生或小学生来说,书写的实验报告也可简单一点,有时也可不要分析于讨论,也可不写实验原理等。
三、探究实验书写一般有七个环节
1.提出问题:就是在生活中发现、提出问题。
2.猜想与假设:发现问题,就要弄清楚问题,在没有搞清楚之前总有基本的猜测和设想,这就是猜想与假设。
3.制定计划与设计实验:有了猜想,就有了实验的目的,再根据实验的目的设计实验方案,制定实验计划,包括取得证据的途径和方法,确定收集证据的范围。包括实验的理论依据(实验原理)、实验器材、实验步骤等。
4.进行实验与收集证据:上一步是动脑、思维活动,这一步是手脑并用的实验过程。
5.分析与论证:通过上面的实验,收集到一些数据,观察到一些现象,对其分析,得出事实与假设的关系,通过归纳、概括等方法,得到结论。
6.评估:这是对整个过程的回顾,将实验数据等证据与已有的科学知识建立联系,不足地方需改进,进一步实验探究。
7.交流与合作:包括同学间的交流与讨论和交给老师批改的书面的实验报告。
如何分析udp报文,从而获取源地址
1、写了一个UDP 的小程序,有一个UDP 的server,而且有UDP的client。
然后执行server和client,然后用tcpdump将该端口的UDP数据报文抓取出来。
执行的过程是这样的。
client向server发送"xiyou"
server向client应答"wangzhe"
client程序在主机example上运行(192.168.1.144)
server程序在主机linux上运行(192.168.1.101)
------------------------------------------------------------------------------------------------------------
2、UDP数据报文。
linux@linux:~$ sudo tcpdump -vvv -X udp port 7777
[sudo] password for linux:
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
11:03:01.923227 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 48)
example.local.43521 linux.7777: [udp sum ok] UDP, length 20
0x0000: 4500 0030 0000 4000 4011 b677 c0a8 0190 E..0..@.@..w....
0x0010: c0a8 0165 aa01 1e61 001c 4c34 7869 796f ...e...a..L4xiyo
0x0020: 7500 0000 0000 0000 0000 0000 0000 0000 u...............
11:03:01.923343 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto UDP (17), length 48)
linux.7777 example.local.43521: [bad udp cksum 6869!] UDP, length 20
0x0000: 4500 0030 0000 4000 4011 b677 c0a8 0165 E..0..@.@..w...e
0x0010: c0a8 0190 1e61 aa01 001c 8473 7761 6e67 .....a.....swang
0x0020: 7a68 6500 0000 0000 0000 0000 0000 0000 zhe.............
由上面的报文可知,有两个UDP数据报文。
第一个报文是example主机上的client向server发送数据。
4500 0030 0000 4000 4011 b677 c0a8 0190 c0a8 0165 这20个数据是IP首部。
aa01 1e61 001c 4c34 这8个字节是UDP的首部。
7869 796f 7500 0000 0000 0000 0000 0000 0000 0000 这20个数据是我用sendto函数发送的
数据。
而将char req[20] = "xiyou" 的ASCII码(16进制)就是:
78 69 79 6f 75 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
第二个报文是linux向主机example做出的应答。
4500 0030 0000 4000 4011 b677 c0a8 0165 c0a8 0190 这20个数据是IP首部。
1e61 aa01 001c 8473 这8个字节是UDP首部。
7761 6e67 7a68 6500 0000 0000 0000 0000 0000 0000 这20个数据是应用层的数据。
而将char reply[20] = "wangzhe"的ASCII码(16进制)就是:
77 61 6e 67 7a 68 65 0 0 0 0 0 0 0 0 0 0 0 0 0
由此看出,应用层的数据没有夹杂其他的参数,全部是数据,均是字符的ASCII码。
-----------------------------------------------------------------------
附带网络程序:
udp_server.c
#include stdio.h
#include stdlib.h
#include sys/socket.h
#include netinet/in.h
#include sys/types.h
#include string.h
int main(void)
{
struct sockaddr_in server,client;
int sockfd;
int cli_len = 0,n;
char req[20] = {0},reply[20] = {0};
sockfd = socket(AF_INET,SOCK_DGRAM,0);
if (sockfd 0) {
perror("socket error!\n");
exit(-1);
}
memset(server,0,sizeof(struct sockaddr_in));
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(7777);
if (bind(sockfd,(struct sockaddr *)server,sizeof(server)) 0) {
perror("bind error!\n");
exit(-1);
}
for (;;) {
cli_len = sizeof(struct sockaddr_in);
n = recvfrom(sockfd,req,20,0,(struct sockaddr *)client,cli_len);
if (n 0) {
perror("recvfrom error!\n");
exit(-1);
}
printf("hello!\n");
strncpy(reply,"wangzhe",sizeof("wangzhe"));
if (sendto(sockfd,reply,20,0,(struct sockaddr *)client,sizeof(client)) != 20) {
perror("sendto error!\n");
exit(-1);
}
}
return 0;
}
-----------------------------------------------------------------------------------------------------------
udp_client.c
#include stdio.h
#include stdlib.h
#include sys/socket.h
#include netinet/in.h
#include sys/types.h
#include string.h
int main(void)
{
int sockfd,n;
struct sockaddr_in server;
char req[20]={0},reply[20]={0};
sockfd = socket(AF_INET,SOCK_DGRAM,0);
if (sockfd 0) {
perror("socket error!\n");
exit(-1);
}
memset(server,0,sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr("192.168.1.101");
server.sin_port = htons(7777);
strncpy(req,"xiyou",sizeof("xiyou"));
printf("sendto req to server:%s\n",req);
if (sendto(sockfd,req,20,0,(struct sockaddr *)server,sizeof(server)) != 20) {
perror("sendto error!\n");
exit(-1);
}
if ((n = recvfrom(sockfd,reply,20,0,(struct sockaddr *)NULL,(int *)NULL)) 0) {
perror("recvfrom error!\n");
exit(-1);
}
printf("recv reply from server :%s\n",reply);
exit(0);
}
--------------------------------------------------------------------------------------------------------
TCP与UDP差异对比分析
写在前面:
公司在做智能硬件方向,所以使用了 TCP、UDP 协议来做通信。过几天我会整理一下两种协议在 Android 上的使用,不过在此之前,还是想先了解一下这两种协议有哪些异同,又有哪些值得注意的地方。本文通过对比分析 TCP 和 UDP 有哪些区别,来帮助这些比较基础的知识点,遇到相应的问题,便可以快速地解决。
TCP:
说到 TCP 建立连接,相信大多数人脑海里肯定可以浮现出一个词,没错就是--“三次握手”。TCP 通过“三次握手”来建立连接,再通过“四次挥手”断开一个连接。在每次挥手中 TCP 做了哪些操作呢?继续往下看:
上图就从客户端和服务端的角度,清楚的展示了 TCP 的三次握手和四次挥手。
可以看到,当 TCP 试图建立连接时,三次握手指的是客户端主动触发了两次,服务端触发了一次。
我们可以先明确一下 TCP 建立连接并且初始化的目标是什么呢?1. 初始化资源 2. 告诉对方我的序列号。
所以三次握手的次序是这样子的:
其中的 2 、3 步骤可以简化为一步,也就是说将 ACK 确认包和 SYN 序列化包一同发送给 Client 端。到此我们就比较简单的解释了 TCP 建立连接的“三次握手”。
UDP:
我们都知道 TCP 是面向连接的、可靠的、有序的传输层协议,而 UDP 是面向数据报的、不可靠的、无序的传输协议,所以 UDP 压根不会建立什么连接。
就好比发短信一样,UDP 只需要知道对方的 ip 地址,将数据报一份一份的发送过去就可以了,其他的作为发送方,都不需要关心。
关于 TCP、UDP 之间数据发送的差异,可以体现二者最大的不同之处:
TCP:
由于 TCP 是建立在两端连接之上的协议,所以理论上发送的数据流不存在大小的限制。但是由于缓冲区有大小限制,所以你如果用 TCP 发送一段很大的数据,可能会截断成好几段,接收方依次的接收。
UDP:
由于 UDP 本身发送的就是一份一份的数据报,所以自然而然的就有一个上限的大小,这个每次 UDP 发送的数据报大小由哪些因素共同决定呢?
先来看第一个因素,UDP 本身协议的报文长度为 2^16 - 1,UDP 包头占 8 个字节,IP 协议本身封装后包头占 20 个字节,所以最终长度为: 2^16 - 1 - 20 - 8 = 65507 字节。
只看第一个因素有点理想化了,因为 UDP 属于不可靠协议,我们应该尽量避免在传输过程中,数据包被分割。所以这里有一个非常重要的概念 MTU -- 也就是最大传输单元。
在 Internet 下 MTU 的值为 576 字节,所以在 internet 下使用 UDP 协议,每个数据报最大的字节数为: 576 - 20 - 8 = 548
TCP:
我们再来谈谈数据的有序性。
对于 TCP 来说,本身 TCP 有着超时重传、错误重传、还有等等一系列复杂的算法保证了 TCP 的数据是有序的,假设你发送了数据 1、2、3,则只要发送端和接收端保持连接时,接收端收到的数据始终都是 1、2、3。
UDP:
而 UDP 协议则要奔放的多,无论 server 端无论缓冲池的大小有多大,接收 client 端发来的消息总是一个一个的接收。并且由于 UDP 本身的不可靠性以及无序性,如果 client 发送了 1、2、3 这三个数据报过来,server 端接收到的可能是任意顺序、任意个数三个数据报的排列组合。
其实大家都知道 TCP 本身是可靠的协议,而 UDP 是不可靠的协议。
TCP:
TCP 内部的很多算法机制让他保持连接的过程中是很可靠的。比如:TCP 的超时重传、错误重传、TCP 的流量控制、阻塞控制、慢热启动算法、拥塞避免算法、快速恢复算法 等等。
所以 TCP 是一个内部原理复杂,但是使用起来比较简单的这么一个协议。
UDP:
UDP 是一个面向非连接的协议,UDP 发送的每个数据报带有自己的 IP 地址和接收方的 IP 地址,它本身对这个数据报是否出错,是否到达不关心,只要发出去了就好了。所以来研究下,什么情况会导致 UDP 丢包:
在文章最后的一部分,聊聊 TCP、UDP 使用场景。
先来说 UDP 的吧,有很多人都会觉得 UDP 与 TCP 相比,在性能速度上是占优势的。因为 UDP 并不用保持一个持续的连接,也不需要对收发包进行确认。但事实上经过这么多年的发展 TCP 已经拥有足够多的算法和优化,在网络状态不错的情况下,TCP 的整体性能是优于 UDP 的。
那在什么时候我们非用 UDP 不可呢?
以上我们说了 UDP 的使用场景,在此之外的其他情况,使用 TCP 准没错。毕竟有一句话嘛。
写在后面:
本文主要是介绍概念,未来会从 Android 的角度来总结 TCP 和 UDP 的使用。
局域网截包程序设计
#define RCVALL_ON 1
#define MAX_ADDR_LEN 16 //点分十进制地址的最大长度
#define MAX_PROTO_TEXT_LEN 16 //子协议名称(如"TCP")最大长度
#define WINSOCK_VERSION MAKEWORD(2, 2)
#pragma comment(lib, "Ws2_32.lib")
#include stdio.h
#include winsock2.h
#include mstcpip.h
#include conio.h
typedef struct iphdr //定义IP首部
{
unsigned char h_lenver; //4位首部长度+4位IP版本号
unsigned char tos; //8位服务类型TOS
unsigned short total_len; //16位总长度(字节)
unsigned short ident; //16位标识
unsigned short frag_and_flags; //3位标志位
unsigned char ttl; //8位生存时间 TTL
unsigned char proto; //8位协议 (TCP, UDP 或其他)
unsigned short checksum; //16位IP首部校验和
unsigned int sourceIP; //32位源IP地址
unsigned int destIP; //32位目的IP地址
}IPHeader;
typedef struct _tcphdr //定义TCP首部
{
USHORT th_sport; //16位源端口
USHORT th_dport; //16位目的端口
unsigned int th_seq; //32位序列号
unsigned int th_ack; //32位确认号
unsigned char th_lenres; //4位首部长度/6位保留字
unsigned char th_flag; //6位标志位
USHORT th_win; //16位窗口大小
USHORT th_sum; //16位校验和
USHORT th_urp; //16位紧急数据偏移量
}TCP_HEADER;
typedef struct _udphdr //定义UDP首部
{
unsigned short uh_sport; //16位源端口
unsigned short uh_dport; //16位目的端口
unsigned short uh_len; //16位长度
unsigned short uh_sum; //16位校验和
}UDP_HEADER;
typedef struct _icmphdr //定义ICMP首部
{
BYTE i_type; //8位类型
BYTE i_code; //8位代码
USHORT i_cksum; //16位校验和
USHORT i_id; //识别号(一般用进程号作为识别号)
USHORT i_seq; //报文序列号
ULONG timestamp; //时间戳
}ICMP_HEADER;
int iTTL,iLEN,iBYTES;
char szSourceIP[MAX_ADDR_LEN], szDestIP[MAX_ADDR_LEN];
int iSourcePort,iDestPort;
int fflag=0;//file flag
#define PACKAGE_SIZE sizeof(IPHeader)+1000
void HandleError(char *func);
//functions
int DecodeTcpPack(char *, int,FILE *); //TCP解包函数
int DecodeUdpPack(char *, int,FILE *); //UDP解包函数
int DecodeIcmpPack(char *, int,FILE *); //ICMP解包函数
//MAIN
int main(int argc, char *argv[])
{
sockaddr_in saSource,saDest;
WSAData wsaData;
char buf[PACKAGE_SIZE];
WSAStartup(WINSOCK_VERSION, wsaData);
SOCKET sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
if(sock == SOCKET_ERROR)
{
HandleError("socket");
WSACleanup();
return -1;
}
//获取本机IP地址
struct sockaddr_in addr;
memset(addr, 0, sizeof(addr));
//addr.sin_addr.S_un.S_addr = inet_addr("192.168.1.101");
char name[256];
PHOSTENT hostinfo;
if( gethostname ( name, sizeof(name)) == 0)
{
if((hostinfo = gethostbyname(name)) != NULL)
{
memcpy((addr.sin_addr.S_un.S_addr) , (struct in_addr *)*hostinfo-h_addr_list , sizeof((struct in_addr *)*hostinfo-h_addr_list ));
}
}
addr.sin_family = AF_INET;
if(bind(sock, (struct sockaddr*)addr, sizeof(addr)) == SOCKET_ERROR)//bind
{
HandleError("bind");
}
//设置SOCK_RAW为SIO_RCVALL,以便接收所有的IP包
int on = RCVALL_ON;
DWORD num;
if(WSAIoctl(sock, SIO_RCVALL, on, sizeof(on), NULL, 0, num, NULL, NULL) == SOCKET_ERROR)
{
HandleError("wsaIoctl set");
}
struct sockaddr_in from;
int fromlen;
int size;
FILE *fp;
if((fp=fopen("log.txt","w+"))==NULL)
{
printf("open file errer,can't save list to file");
fflag=1;
}
//侦听IP报文
while(!kbhit())
{
memset(buf, 0, sizeof(num));
memset(from, 0, sizeof(from));
fromlen = sizeof(from);
size=recvfrom(sock, buf, PACKAGE_SIZE, 0, (struct sockaddr*)from, fromlen);
if(size == SOCKET_ERROR)
{
if(WSAGetLastError() == WSAEMSGSIZE)
{
HandleError("recvfrom");
continue;
}
}
IPHeader *iph=(IPHeader *)buf;
/**/
//源地址
saSource.sin_addr.s_addr = iph-sourceIP;
strncpy(szSourceIP, inet_ntoa(saSource.sin_addr), MAX_ADDR_LEN);
//目的地址
saDest.sin_addr.s_addr = iph-destIP;
strncpy(szDestIP, inet_ntoa(saDest.sin_addr), MAX_ADDR_LEN);
iTTL = iph-ttl;
//计算IP首部的长度
int IpHeadLen = 4 * (iph-h_lenver 0xf);
//根据协议类型分别调用相应的函数
switch(iph-proto)
{
case IPPROTO_ICMP:
DecodeIcmpPack(buf+IpHeadLen, size,fp);
break;
case IPPROTO_IGMP:
printf("IGMP ");
printf("%15s: -%15s: ", szSourceIP, szDestIP);
printf("%d",size);
printf("%s/n", buf);
break;
case IPPROTO_TCP:
DecodeTcpPack((buf+IpHeadLen),size,fp);
break;
case IPPROTO_UDP:
DecodeUdpPack(buf+IpHeadLen, size,fp);
break;
default:
printf("unknown datagram from %s/n", inet_ntoa(from.sin_addr));
printf("%s/n", buf);
break;
}//end switch
Sleep(200);
}//end while
fclose(fp);
closesocket(sock);
WSACleanup();
printf("Stopped!/n");
getch();
return 0;
}//end of main
//TCP解包程序
int DecodeTcpPack(char * TcpBuf, int iBufSize,FILE *fp)
{
unsigned char FlagMask;FlagMask = 1;
int i;
TCP_HEADER *tcph;
tcph = (TCP_HEADER*)TcpBuf;
//计算TCP首部长度
int TcpHeadLen = tcph-th_lenres4;
TcpHeadLen *= sizeof(unsigned long);
char *TcpData=TcpBuf+TcpHeadLen;
iSourcePort = ntohs(tcph-th_sport);
iDestPort = ntohs(tcph-th_dport);
//输出
printf("TCP ");
printf("%15s:%5d -%15s:%5d ", szSourceIP, iSourcePort, szDestIP, iDestPort);
printf("TTL=%3d ", iTTL);
if(fflag==1)
//判断TCP标志位
for( i=0; i6; i++ )
{
if((tcph-th_flag) FlagMask)
printf("1");
else printf("0");
FlagMask=FlagMask1;
}
printf(" bytes=%4d", iBufSize);
printf("/n");
if(fflag=1)//写入文件
fprintf(fp,"TCP %15s:%5d -%15s:%5d TTL=%3d ------ bytes=%4d/n"
,szSourceIP, iSourcePort, szDestIP, iDestPort, iTTL,iBufSize);
return 0;
}
//UDP解包程序
int DecodeUdpPack(char * UdpBuf, int iBufSize,FILE *fp)
{
UDP_HEADER *udph;
udph = (UDP_HEADER*)UdpBuf;
iSourcePort = ntohs(udph-uh_sport);
iDestPort = ntohs(udph-uh_dport);
//输出
printf("UDP ");
printf("%15s:%5d -%15s:%5d ", szSourceIP, iSourcePort, szDestIP, iDestPort);
printf("TTL=%3d ", iTTL);
printf("Len=%4d ", ntohs(udph-uh_len));
printf("bytes=%4d", iBufSize);
printf("/n");
if(fflag=1)//写入文件
fprintf(fp,"UDP %15s:%5d -%15s:%5d TTL=%3d Len=%4d bytes=%4d/n"
,szSourceIP, iSourcePort, szDestIP, iDestPort, iTTL, ntohs(udph-uh_len), iBufSize);
return 0;
}
//ICMP解包程序
int DecodeIcmpPack(char * IcmpBuf, int iBufSize,FILE *fp)
{
ICMP_HEADER * icmph;
icmph = (ICMP_HEADER * )IcmpBuf;
int iIcmpType = icmph-i_type;
int iIcmpCode = icmph-i_code;
//输出
printf("ICMP ");
printf("%15s -%15s ", szSourceIP, szDestIP);
printf("TTL=%3d ", iTTL);
printf("Type%2d,%d ",iIcmpType,iIcmpCode);
printf("bytes=%4d", iBufSize);
printf("/n");
if(fflag=1)//写入文件
fprintf(fp,"ICMP %15s -%15s TTL=%3d Type%2d,%d bytes=%4d"
, szSourceIP, szDestIP, iTTL,iIcmpType,iIcmpCode, iBufSize);
return 0;
}
void HandleError(char *func)
{
char info[65]= {0};
_snprintf(info, 64, "%s: %d/n", func, WSAGetLastError());
printf(info);
}