004.UDP--拼接UDP数据包,构造ip头和udp头通信(使用原始套接字)

摘要:
)后通过原始套接字将包发出去。server端收到数据后,打印UDP数据并发送确认消息,client收到yes后将其打印。二.其中:client端IP:192.168.11.104端口:8600server端IP:192.168.11.105端口:8686三.注意事项:1.运行原始套接字socket需要有root权限。

一.大致流程:

建立一个client端,一个server端,自己构建IP头和UDP头,写入数据(hello,world!)后通过原始套接字(SOCK_RAW)将包发出去。

server端收到数据后,打印UDP数据并发送确认消息(yes),client收到yes后将其打印。

二.其中:

client端IP:192.168.11.104 端口:8600

server端IP:192.168.11.105 端口:8686

三.注意事项:

1.运行原始套接字socket需要有root权限。

2.注意主机字节序和网络字节序的

四.涉及的数据结构

1.ip部分的结构图:

004.UDP--拼接UDP数据包,构造ip头和udp头通信(使用原始套接字)第1张

2.ip结构体定义:

struct iphdr       /*该结构体在<netinet/ip.h>中定义 */{
#if __BYTE_ORDER == __LITTLE_ENDIAN  /* 如果是小端字节序 */unsigned int ihl:4;     /*首部长度*/unsigned int version:4; /*版本 */
#elif __BYTE_ORDER == __BIG_ENDIANunsigned int version:4;
    unsigned int ihl:4;
#else# error    "Please fix <bits/endian.h>"
#endifu_int8_t tos;           /*区分服务 */u_int16_t tot_len;      /*总长度 */u_int16_t id;           /*标识 */u_int16_t frag_off;     /*标志(3位)+片偏移(13位) */u_int8_t ttl;           /*生存时间 */u_int8_t protocol;      /*协议 */u_int16_t check;        /*首部检验和 */u_int32_t saddr;        /*源地址 */u_int32_t daddr;        /*目的地址 */
    /*The options start here. */};

3.udp数据包的结构图:

004.UDP--拼接UDP数据包,构造ip头和udp头通信(使用原始套接字)第2张

4.udp结构体定义:

struct udphdr  /*该结构体在<netiniet/udp.h>中定义 */{
  u_int16_t source;  /*源端口*/u_int16_t dest;    /*目的端口*/u_int16_t len;     /*长度*/u_int16_t check;   /*校验和*/};

五.实现如下:

client端:

1 /*
2 ============================================================================
3 Name        : test_client.c
4 Author      : huh
5 Version     :
6 Copyright   : ---notice---
7 Description : Hello World in C, Ansi-style
8 ============================================================================
9  */
10 
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <stdio.h>
14 #include <netinet/in.h>
15 #include <arpa/inet.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <netinet/ip_icmp.h>
20 #include <netinet/udp.h>
21 
22 #define MAXLINE 1024*10
23 
24 struct udp_front  //udp
25 {
26 uint32_t srcip;
27 uint32_t desip;
28 u_int8_t zero;
29 u_int8_t protocol;
30 u_int16_t len;
31 };
32 
33 u_int16_t in_chksum(u_int16_t *addr, intlen);
34 u_int16_t udp_check(char *sendbuf, int len, const structudp_front front);
35 int make_message(char sendbuf[], intsend_buf_len, uint32_t src_ip, u_int16_t src_port, uint32_t des_ip, u_int16_t des_port);
36 
37 intmain()
38 {
39     intraw_sockfd;
40     int size = 1024*50;
41     charsend_message[MAXLINE];
42     structsockaddr_in server_address;
43     //创建原始套接字
44     raw_sockfd =socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
45     //创建套接字地址
46     bzero(&server_address,sizeof(server_address));
47     server_address.sin_family =AF_INET;
48     server_address.sin_addr.s_addr = inet_addr("192.168.11.105");
49     //设置套接字为随数据包含IP首部(设置这个选项后需要我们手动写入IP头)
50     setsockopt(raw_sockfd, IPPROTO_IP, IP_HDRINCL, &size, sizeof(size));
51 
52     intlen;
53     bzero(&send_message, sizeof(send_message));
54     //拼接完整的UDP数据包(IP头+UDP头+数据)
55     int mesg_len = make_message(send_message, MAXLINE, inet_addr("192.168.11.104"), 8600, inet_addr("192.168.11.105"), 8686);
56     //将IP数据包发送出去
57     sendto(raw_sockfd, send_message, mesg_len, 0, (struct sockaddr *)&server_address, sizeof(server_address));
58 close(raw_sockfd);
59     //
60     //下面我们开始接受服务器返回的包
61     intclient_sockfd;
62     intserver_len;
63     charrecv_message[MAXLINE];
64     structsockaddr_in server_addr;
65     client_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
66     server_addr.sin_family =AF_INET;
67     server_addr.sin_addr.s_addr = inet_addr("192.168.11.104");
68     server_addr.sin_port = htons(8600);
69     server_len = sizeof(server_address);
70     bind(client_sockfd, (struct sockaddr *)&server_addr, server_len);
71 
72     bzero(&recv_message, sizeof(recv_message));
73        len = recvfrom(client_sockfd, recv_message, MAXLINE, 0, NULL, NULL);
74        printf("收到的应答:%s
",recv_message);
75     return 0;
76 }
77 
78 //拼接IP数据报
79 int make_message(char sendbuf[], intsend_buf_len, uint32_t src_ip, u_int16_t src_port, uint32_t des_ip, u_int16_t des_port)
80 {
81     char message[1005];
82     bzero(message, sizeof(message));
83     strcpy(message,"hello,world!");
84     printf("message len:%d
",strlen(message));
85     struct iphdr *ip;
86     ip = (struct iphdr *)sendbuf;
87     ip->ihl = sizeof(struct iphdr) >> 2; //首部长度
88     ip->version = 4;   //ip协议版本
89     ip->tos = 0;   //服务类型字段
90     ip->tot_len = 0;   //总长度
91     ip->id = 1000;   //
92     ip->frag_off = 0;
93     ip->ttl = 128;
94     ip->protocol =IPPROTO_UDP;
95     ip->check = 0;  //内核会算相应的效验和
96     ip->saddr =src_ip;
97     ip->daddr =des_ip;
98 
99     structudp_front front;
100     front.srcip =src_ip;
101     front.desip =des_ip;
102     front.len = htons(8+strlen(message));
103     front.protocol = 17;
104     front.zero = 0;
105 
106     struct udphdr *udp;
107     udp = (struct udphdr *)(sendbuf + sizeof(structiphdr));
108     udp->source = htons(src_port);  //源端口
109     udp->dest = htons(des_port);    //目的端口
110     udp->check = 0;   //效验和,效验整个udp数据报
111     strcpy((sendbuf+20+8), message);
112     udp->len = htons(8+strlen(message)); //udp数据报总长度
113 
114     udp->check = udp_check((sendbuf+20), 8+strlen(message), front);
115 
116     ip->tot_len = htons(20 + 8 + strlen(message));   //总长度
117     printf("ip->tot_len:%d
",ip->tot_len);
118     ip->check = in_chksum((unsigned short *)sendbuf, 20);
119 
120     return ntohs(ip->tot_len);
121 }
122 
123 //计算udp效验和
124 unsigned short udp_check(char *sendbuf, int len, const structudp_front front)
125 {
126     charstr[MAXLINE];
127     bzero(&str, MAXLINE);
128     bcopy(&front, str, sizeof(front));
129     bcopy(sendbuf, str+sizeof(front), len);
130     struct udp_front *ptr;
131     ptr = (struct udp_front *)str;
132     char *s;
133     s = (str+20);
134     return in_chksum((unsigned short *)str, sizeof(front)+len);
135 }
136 
137 //效验和算法
138 uint16_t in_chksum(uint16_t *addr, intlen)
139 {
140     int nleft =len;
141     uint32_t sum = 0;
142     uint16_t *w =addr;
143     uint16_t answer = 0;
144     //把ICMP报头二进制数据以2字节为单位累加起来
145     while (nleft > 1)
146 {
147         sum += *w++;
148         nleft -= 2;
149 }
150     if (nleft == 1)
151 {
152         *(unsigned char *)(&answer) = *(unsigned char *)w;
153         sum +=answer;
154 }
155     sum = (sum>>16) + (sum&0xffff);
156     sum += (sum>>16);
157     answer = ~sum;
158     returnanswer;
159 }

server端:

server端是一个简单的收包服务器,监听8686端口,当有udp数据包到来时,打印信息并返回给client一个信息。

004.UDP--拼接UDP数据包,构造ip头和udp头通信(使用原始套接字)第3张004.UDP--拼接UDP数据包,构造ip头和udp头通信(使用原始套接字)第4张
1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <stdio.h>
4 #include <netinet/in.h>
5 #include <arpa/inet.h>
6 #include <unistd.h>
7 #include <stdlib.h>
8 #include <string.h>
9 
10 #define HOST_IP "192.168.11.105"
11 #define HOST_PORT 8686
12 
13 #define MAXLINE 1024*50
14 
15 intmain()
16 {
17     intserver_sockfd;
18     intserver_len, client_len;
19     structsockaddr_in server_address;
20     structsockaddr_in client_address;
21 
22     server_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
23 
24     server_address.sin_family =AF_INET;
25     server_address.sin_addr.s_addr =inet_addr(HOST_IP);
26     server_address.sin_port =htons(HOST_PORT);
27 
28     server_len = sizeof(server_address);
29     bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
30 
31     for( ; ; )
32 {
33         intlen;
34         charrecv_mesg[MAXLINE];
35         char send_mesg[20];
36         client_len = sizeof(structsockaddr_in);
37         printf("server2 waiting!
");
38         len = recvfrom(server_sockfd, recv_mesg, MAXLINE, 0, (struct sockaddr *) &client_address, (socklen_t *) &client_len);
39         printf("收到包的长度为:%d
",len);
40         printf("%s
",recv_mesg);
41         strcpy(send_mesg,"yes");
42         sendto(server_sockfd, send_mesg, strlen(send_mesg), 0, (struct sockaddr *) &client_address, client_len);  //将包发出去
43 }
44     return 0;
45 }
server.c

免责声明:文章转载自《004.UDP--拼接UDP数据包,构造ip头和udp头通信(使用原始套接字)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【转】makefile的双冒号规则二分查找之新手篇——函数使用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Android编译大全(六)

6.2. makefile文件控制整个android系统编译的make文件。其内容如下: ### DO NOT EDIT THIS FILE ### include build/core/main.mk ### DO NOT EDIT THIS FILE ###   可以看出,实际上控制编译的文件是:build/core/main.mk 6.3. Make...

图解物联网---物联网服务的系统开发

物联网系统化就是应用传感器等各类设备来形成一个持续解决问题的机制。也就是说,不只用传感器进行测量,还通过对测量数据的监测和分析来发现能量损耗,预测机器故障,从而创造出新的信息和价值。 对物联网服务而言,系统的主体是设备,因此在进行系统开发时,也有一些是设备方面需要留意的地方而 1、物联网系统开发的问题 物联网服务需要多方面的知识。除了在服务器端运行的应用...

linux上TCP和UDP测试延迟的方法

原文: 测试TCP监听协议的加速效果 https://help.aliyun.com/document_detail/158772.html?spm=a2c4g.11186623.2.20.20326da8d8Af0p#task-2447838 测试UDP监听协议的加速效果 https://help.aliyun.com/document_detail/1...

消息队列之 ActiveMQ

简介 ActiveMQ 特点 ActiveMQ 是由 Apache 出品的一款开源消息中间件,旨在为应用程序提供高效、可扩展、稳定、安全的企业级消息通信。 它的设计目标是提供标准的、面向消息的、多语言的应用集成消息通信中间件。ActiveMQ 实现了 JMS 1.1 并提供了很多附加的特性,比如 JMX 管理、主从管理、消息组通信、消息优先级、延迟接收...

关于malloc和sizeof的用法

问题1: 1.L.elem = (ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));2.newbase = (ElemType *)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType)); 其中L是已经定义的线性表,LIST_INIT_SIZ...

记:Android NDK 的配置和使用

一、NDK配置:   从ndk r7开始,不再需要cygwin;   选择项目单击右键,点击Properties,在Builders窗口中新建一个program,输入名称;   在main标签页的location选择ndk目录中的ndk-build.cmd,在Working Directory选择当前项目;        在Refresh标签页,勾选如下选...