一.大致流程:

建立一个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部分的结构图:

2.ip结构体定义:

struct iphdr       /* 该结构体在<netinet/ip.h>中定义 */
{
#if __BYTE_ORDER == __LITTLE_ENDIAN /* 如果是小端字节序 */
unsigned int ihl:; /*首部长度*/
unsigned int version:; /* 版本 */
#elif __BYTE_ORDER == __BIG_ENDIAN
unsigned int version:;
unsigned int ihl:;
#else
# error "Please fix <bits/endian.h>"
#endif
u_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数据包的结构图:

4.udp结构体定义:

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

五.实现如下:

client端:

 /*
============================================================================
Name : test_client.c
Author : huh
Version :
Copyright : ---notice---
Description : Hello World in C, Ansi-style
============================================================================
*/ #include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h> #define MAXLINE 1024*10 struct udp_front //udp
{
uint32_t srcip;
uint32_t desip;
u_int8_t zero;
u_int8_t protocol;
u_int16_t len;
}; u_int16_t in_chksum(u_int16_t *addr, int len);
u_int16_t udp_check(char *sendbuf, int len, const struct udp_front front);
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); int main()
{
int raw_sockfd;
int size = *;
char send_message[MAXLINE];
struct sockaddr_in server_address;
//创建原始套接字
raw_sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
//创建套接字地址
bzero(&server_address,sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("192.168.11.105");
//设置套接字为随数据包含IP首部(设置这个选项后需要我们手动写入IP头)
setsockopt(raw_sockfd, IPPROTO_IP, IP_HDRINCL, &size, sizeof(size)); int len;
bzero(&send_message, sizeof(send_message));
//拼接完整的UDP数据包(IP头+UDP头+数据)
int mesg_len = make_message(send_message, MAXLINE, inet_addr("192.168.11.104"), , inet_addr("192.168.11.105"), );
//将IP数据包发送出去
sendto(raw_sockfd, send_message, mesg_len, , (struct sockaddr *)&server_address, sizeof(server_address));
close(raw_sockfd);
//
//下面我们开始接受服务器返回的包
int client_sockfd;
int server_len;
char recv_message[MAXLINE];
struct sockaddr_in server_addr;
client_sockfd = socket(AF_INET, SOCK_DGRAM, );
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("192.168.11.104");
server_addr.sin_port = htons();
server_len = sizeof(server_address);
bind(client_sockfd, (struct sockaddr *)&server_addr, server_len); bzero(&recv_message, sizeof(recv_message));
len = recvfrom(client_sockfd, recv_message, MAXLINE, , NULL, NULL);
printf("收到的应答:%s\n",recv_message);
return ;
} //拼接IP数据报
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)
{
char message[];
bzero(message, sizeof(message));
strcpy(message,"hello,world!");
printf("message len:%d\n",strlen(message));
struct iphdr *ip;
ip = (struct iphdr *)sendbuf;
ip->ihl = sizeof(struct iphdr) >> ; //首部长度
ip->version = ; //ip协议版本
ip->tos = ; //服务类型字段
ip->tot_len = ; //总长度
ip->id = ; //
ip->frag_off = ;
ip->ttl = ;
ip->protocol = IPPROTO_UDP;
ip->check = ; //内核会算相应的效验和
ip->saddr = src_ip;
ip->daddr = des_ip; struct udp_front front;
front.srcip = src_ip;
front.desip = des_ip;
front.len = htons(+strlen(message));
front.protocol = ;
front.zero = ; struct udphdr *udp;
udp = (struct udphdr *)(sendbuf + sizeof(struct iphdr));
udp->source = htons(src_port); //源端口
udp->dest = htons(des_port); //目的端口
udp->check = ; //效验和,效验整个udp数据报
strcpy((sendbuf++), message);
udp->len = htons(+strlen(message)); //udp数据报总长度 udp->check = udp_check((sendbuf+), +strlen(message), front); ip->tot_len = htons( + + strlen(message)); //总长度
printf("ip->tot_len:%d\n",ip->tot_len);
ip->check = in_chksum((unsigned short *)sendbuf, ); return ntohs(ip->tot_len);
} //计算udp效验和
unsigned short udp_check(char *sendbuf, int len, const struct udp_front front)
{
char str[MAXLINE];
bzero(&str, MAXLINE);
bcopy(&front, str, sizeof(front));
bcopy(sendbuf, str+sizeof(front), len);
struct udp_front *ptr;
ptr = (struct udp_front *)str;
char *s;
s = (str+);
return in_chksum((unsigned short *)str, sizeof(front)+len);
} //效验和算法
uint16_t in_chksum(uint16_t *addr, int len)
{
int nleft = len;
uint32_t sum = ;
uint16_t *w = addr;
uint16_t answer = ;
//把ICMP报头二进制数据以2字节为单位累加起来
while (nleft > )
{
sum += *w++;
nleft -= ;
}
if (nleft == )
{
*(unsigned char *)(&answer) = *(unsigned char *)w;
sum += answer;
}
sum = (sum>>) + (sum&0xffff);
sum += (sum>>);
answer = ~sum;
return answer;
}

server端:

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

 #include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h> #define HOST_IP "192.168.11.105"
#define HOST_PORT 8686 #define MAXLINE 1024*50 int main()
{
int server_sockfd;
int server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address; server_sockfd = socket(AF_INET, SOCK_DGRAM, ); server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr(HOST_IP);
server_address.sin_port = htons(HOST_PORT); server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr *)&server_address, server_len); for( ; ; )
{
int len;
char recv_mesg[MAXLINE];
char send_mesg[];
client_len = sizeof(struct sockaddr_in);
printf("server2 waiting!\n");
len = recvfrom(server_sockfd, recv_mesg, MAXLINE, , (struct sockaddr *) &client_address, (socklen_t *) &client_len);
printf("收到包的长度为:%d\n",len);
printf("%s\n",recv_mesg);
strcpy(send_mesg,"yes");
sendto(server_sockfd, send_mesg, strlen(send_mesg), , (struct sockaddr *) &client_address, client_len); //将包发出去
}
return ;
}

server.c

004.UDP--拼接UDP数据包,构造ip头和udp头通信(使用原始套接字)的更多相关文章

  1. udp拼接传递数据包

    1.拼接项少 pl = ["<0112>","<32>","<1024x768>","< ...

  2. linux原始套接字(3)-构造IP_TCP发送与接收

    一.概述                                                    tcp报文封装在ip报文中,创建tcp的原始套接字如下: sockfd = socket ...

  3. ETHERNET数据包格式( IP & UDP & ICMP & ARP )

    ETHERNET数据包格式( IP & UDP & ICMP & ARP ) ETHERNET数据包格式 一.ETHERNET 数据包的协议类型 TYPE 的值为 0x0800 ...

  4. 以太网数据包、IP包、TCP/UDP 包的结构(转)

    源:以太网数据包.IP包.TCP/UDP 包的结构 版本号(Version):长度4比特.标识目前采用的IP协议的版本号.一般的值为0100(IPv4),0110(IPv6). IP包头长度(Head ...

  5. TCP和UDP 协议发送数据包的大小

    在进行UDP编程的时候,我们最容易想到的问题就是,一次发送多少bytes好? 当然,这个没有唯一答案,相对于不同的系统,不同的要求,其得到的答案是不一样的,这里仅对像ICQ一类的发送聊天消息的情况作分 ...

  6. C++ Win 32 使用原始套接字获取所有ip数据包并分析(包括ping包)

    /*页面编码:GBK 开发环境 VS2019 */ #define _WINSOCK_DEPRECATED_NO_WARNINGS#include <iostream>#include&l ...

  7. python使用原始套接字 解析原始ip头数据

    使用底层套接字解码底层流量,是这次做的重点工作. 首先来捕获第一个包 # coding:utf-8import socket # 监听的主机IP host = "192.168.1.100& ...

  8. 005.TCP--拼接TCP头部IP头部,实现TCP三次握手的第一步(Linux,原始套接字)

    一.目的: 自己拼接IP头,TCP头,计算效验和,将生成的报文用原始套接字发送出去. 若使用tcpdump能监听有对方服务器的包回应,则证明TCP报文是正确的! 二.数据结构: TCP首部结构图: s ...

  9. linux原始套接字(4)-构造IP_UDP

    一.概述                                                    同上一篇tcp一样,udp也是封装在ip报文里面.创建UDP的原始套接字如下: (soc ...

随机推荐

  1. 编译安装php-amq扩展

    用途:这个扩展是用来操作rabbitmq服务端的 一.安装总括 1.编译安装librabbitmq库 这是一个开源c语言的库.用来与rabbitmq进行通信 而php的php-amqp扩展就是使用这个 ...

  2. # 关于Apache的25个初中级面试题

    注:本文从自己的Markdown博客复制出,除标题字体加粗.代码风格改变.图片重新上传外其余均为markdown语法. 标签(空格分隔): LAMP --- 原文:[关于Apache的25个初中级面试 ...

  3. HTTP错误大全 404 200 501 502 505

    HTTP错误 大全 403 401 400 404 304 200 HTTP 400 - 请求无效 HTTP 401.1 - 未授权:登录失败 HTTP 401.2 - 未授权:服务器配置问题导致登录 ...

  4. MongoDB环境准备

    1.安装MongoDB MongoDB的安装非常简单,只需要将下载的MongoDB的压缩文件解压到任意目录,并将其中的bin目录加入到系统的path环境变量中即可 2.启动MongoDB 在启动Mon ...

  5. JSON.NET 使用技巧

    1. 序列化相关技巧 通过特性忽略某些属性 有时候我们会有这样的需求,我们只需要序列化实体类中的一部分属性,这时候我们可以通过声明忽略掉一些我们不需要序列化的属性,有两种方式可以使用么达到这个目标: ...

  6. Entity Framework 笔记(一)

    Entity Framework概述 EF是一个对象关系映射(ORM)框架,允许开发人员使用特定于域的对象关系型数据,开发人员通常不需要编写大量的数据访问代码.使用EF,开发者可以利用LINQ进行查询 ...

  7. Bootstrap源码分析之transition、affix

    一.Transition(过滤) 作为一个基础支持的组件,被其他组件多次引用.实现根据浏览器支持transition的能力,然后绑定动画的结束事件:首先:创建一个Element:然后:迭代查看此元素支 ...

  8. Popmotion – 小巧,灵活的 JavaScript 运动引擎

    Popmotion 是一个只有12KB的 JavaScript 运动引擎,可以用来实现动画,物理效果和输入跟踪.原生的DOM支持:CSS,SVG,SVG路径和DOM属性的支持,开箱即用.Popmoti ...

  9. go语言条件语句 if else

    示例: if a < 5 { return 0 } else { return 1 } 关于条件语句,需要注意以下几点:  条件语句不需要使用括号将条件包含起来():  无论语句体内有几条语 ...

  10. Autodesk的照片建模云服务—Autodesk ReCap 360 photo

    现实捕捉技术方兴未艾,简单的讲现实捕捉技术就是把现实中的现状信息数字化到计算机中以便做进一步的处理.对于不同的应用目的会有不同的捕捉设备,工程或传媒娱乐行业中经常用到的肯定就是三维模型了.那如何得到三 ...