大致流程:
建立一个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.注意主机字节序和网络字节序的转
实现如下:
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, int len); 34 u_int16_t udp_check(char *sendbuf, int len, const struct udp_front front); 35 int make_message(char sendbuf[], int send_buf_len, uint32_t src_ip, u_int16_t src_port, uint32_t des_ip, u_int16_t des_port); 36 37 int main() 38 { 39 int raw_sockfd; 40 int size = 1024*50; 41 char send_message[MAXLINE]; 42 struct sockaddr_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 int len; 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 int client_sockfd; 62 int server_len; 63 char recv_message[MAXLINE]; 64 struct sockaddr_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\n",recv_message); 75 return 0; 76 } 77 78 //拼接IP数据报 79 int make_message(char sendbuf[], int send_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\n",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 struct udp_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(struct iphdr)); 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 = (20 + 8 + strlen(message)); //总长度 117 printf("ip->tot_len:%d\n",ip->tot_len); 118 ip->check = in_chksum((unsigned short *)sendbuf, 20); 119 120 return (ip->tot_len); 121 } 122 123 //计算udp效验和 124 unsigned short udp_check(char *sendbuf, int len, const struct udp_front front) 125 { 126 char str[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, int len) 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 return answer; 159 }
server端:
1 /* 2 ============================================================================ 3 Name : test_server.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 20 #define MAXLINE 1024*50 21 22 int main() 23 { 24 int server_sockfd; 25 int server_len, client_len; 26 struct sockaddr_in server_address; 27 struct sockaddr_in client_address; 28 29 server_sockfd = socket(AF_INET, SOCK_DGRAM, 0); 30 31 server_address.sin_family = AF_INET; 32 server_address.sin_addr.s_addr = inet_addr("192.168.11.105"); 33 server_address.sin_port = htons(8686); 34 35 server_len = sizeof(server_address); 36 bind(server_sockfd, (struct sockaddr *)&server_address, server_len); 37 38 for( ; ; ) 39 { 40 int len; 41 char recv_mesg[MAXLINE]; 42 char send_mesg[20]; 43 client_len = sizeof(struct sockaddr_in); 44 printf("server2 waiting!\n"); 45 len = recvfrom(server_sockfd, recv_mesg, MAXLINE, 0, (struct sockaddr *) &client_address, (socklen_t *) &client_len); 46 printf("收到包的长度为:%d\n",len); 47 printf("%s\n",recv_mesg); 48 strcpy(send_mesg,"yes"); 49 sendto(server_sockfd, send_mesg, strlen(send_mesg), 0, (struct sockaddr *) &client_address, client_len); //将包发出去 50 ; 51 } 52 return 0; 53 }
时间: 2024-12-20 09:11:54