最近在写网络安全实验,感觉欠缺的东西太多了,边写边总结记录一下。暂时有点乱,等实验写完搞懂了再整理
Linux+C
地址转换
-
头文件:
<arpa/inet.h>
; -
函数原型:
in_addr_t inet_addr(const char* cp)
:将字符串形式的IP地址 -> 网络字节顺序 的整型值 -
返回值:
in_addr_t
一般为32位unsigned int
,若字符串有效,则将字符串转换为32位二进制网络字节序的IPV4地址;否则,为INADDR_NONE
;
char *inet_ntoa(struct in_addr)
:网络字节顺序的整型值 ->字符串形式的IP地址(点分十进制)
- 参数:in_addr为结构体,表示32位IP地址
struct in_addr{
in_addr_t s_addr; //32位unsigned int IPv4地址
}
sockaddr和sockaddr_in
sockaddr :
- 头文件:
<sys/socket.h>
- 结构体定义:
struct sockaddr {
sa_family_t sin_family;//地址族
char sa_data[14]; //14字节,包含套接字中的目标地址和端口信息 };
sockaddr_in:
- 头文件:
<netinet/in.h>或<arpa/inet.h>
- 结构体定义:
struct sockaddr_in{
sa_family_t sin_family; //套接字地址结构的地址族
uint16_t sin_port; //16位TCP/UDP端口号
struct in_addr sin_addr; //32位IP地址
char sin_zero[8]; //不使用
}
区别与联系:
- sockaddr通用套接字地址,bind、connect、recvfrom、sento等函数参数
- sockaddr_in:网络编程环境下套接字的地址形式;
- 可以先把sockaddr_in变量赋值后,强制类型转换后传入sockaddr作参数的函数 例如:
struct sockaddr_in mysock;
sockfd = socket(AF_INET,SOCK_STREAM,0); //获得fd
bzero(&mysock,sizeof(mysock)); //初始化结构体
mysock.sin_family = AF_INET; //设置地址家族
mysock.sin_port = htons(800); //设置端口
mysock.sin_addr.s_addr = inet_addr("192.168.1.0"); //设置地址
bind(sockfd,(struct sockaddr *)&mysock,sizeof(struct sockaddr); /* bind的时候进行转化 */
IPv4头部:
//struct ip和struct iphdr是同一基础结构的两个不同定义,它们是从不同的地方引入的。
//struct ip在<netinet / ip.h>中定义,它是UNIX系统上的合理标准头。
//struct iphdr在<linux / ip.h>中定义。该头文件(和结构)特定于Linux,在其他操作系统中将不存在。
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos;
__be16 -tot_len;
__be16 -id;
__be16 -frag_off;
__u8 ttl;
__u8 protocol;
__be16 -check;
__be32 -saddr;
__be32 -daddr;
};
struct ip {
#if BYTE_ORDER == LITTLE_ENDIAN
u_char ip_hl:4, /* header length */
ip_v:4; /* version */
#endif
#if BYTE_ORDER == BIG_ENDIAN
u_char ip_v:4, /* version */
ip_hl:4; /* header length */
#endif
u_char ip_tos; /* type of service */
short ip_len; /* total length */
u_short ip_id; /* identification */
short ip_off; /* fragment offset field */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};
TCP头部
struct tcphdr {
__be16 source; //16位源端口号
__be16 dest; //16位目的端口号
//每个tcp段都包源和目的端口号,用于寻找发送端和接受端的应用进程。
//这两个端口号加上ip报头中的源ip和目的ip,来确定一个唯一的TCP连接。
__be32 seq;
//此次发送的数据在整个报文段中的起始字节数。此序号用来标识从tcp发送端向tcp接受端发送的数据字节流,
//seq表示在这个报文段中的第一个数据字节。如果将字节流看做在两个应用程序间的单向流动,
//则tcp用序号对每个字节进行计数。32 bit的无符号数。为了安全起见,它的初始值是一个随机生成的数,
//它到达2的32次方-1后又从零开始。
__be32 ack_seq;
//是下一个期望接收的字节,确认序号应当是上次已成功接收的序号+1,只有ack标志为1时确认序号字段才有效。
//一旦一个连接已经建立了,ack总是=1
#if defined(__LITTLE_ENDIAN_BITFIELD) //小端
__u16 res1:4, // 保留位
doff:4,
//tcp头部长度,指明了在tcp头部中包含了多少个32位的字。由于options域的长度是可变的,
//所以整个tcp头部的长度也是变化的。4bit可表示最大值15,故15*32=480bit=60字节,所以tcp首部最长60字节
//然后,没有任选字段,正常的长度是20字节
fin:1, //发端完成发送任务
syn:1, //同步序号用来发起一个连接
rst:1, //重建连接
psh:1, //接收方应该尽快将这个报文段交给应用层
ack:1, //一旦一个连接已经建立了,ack总是=1
urg:1, //紧急指针有效
ece:1,
cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u16 doff:4,
res1:4,
cwr:1,
ece:1,
urg:1,
ack:1,
psh:1,
rst:1,
syn:1,
fin:1;
#else
#error "Adjust your <asm/byteorder.h> defines"
#endif
__be16 window;
//窗口大小,单位字节数,指接收端正期望接受的字节,16bit,故窗口大小最大为16bit=1111 1111 1111 1111(二进制)
//=65535(十进制)字节
__sum16 check;
//校验和校验的是整个tcp报文段,包括tcp首部和tcp数据,这是一个强制性的字段,一定是由发端计算和存储,
//并由收端进行验证。
__be16 urg_ptr; //指示紧急数据在当前数据段中的位置
};
|----------------|----------------|-------------
| source | dest |
|----------------|----------------|
| seq |
|---------------------------------|
| ack_seq | 20 Bytes
|----|----|------|----------------|
|doff|res1| | window |
|----|----|------|----------------|
| check | urg_ptr |
|----------------|----------------|-------------
| options | 4 Bytes
|---------------------------------|
TCP伪首部
参考博客:jiangqin115
- 概念:信息是从数据报所在IP分组头的分组头中提取的,既不向下传送也不向上递交,而仅仅是为计算校验和。
- 既校验了TCP&UDP用户数据的源端口号和目的端口号以及TCP&UDP用户数据报的数据部分,又检验了IP数据报的源IP地址和目的地址。伪报头保证TCP&UDP数据单元到达正确的目的地址
-----------------------------------------
| 32bit Source IP address |
-----------------------------------------
| 32bit Destination IP addr |
-----------------------------------------
| 0 | 8bit Proto| 16bit header length|
-----------------------------------------
//伪头部:用于TCP/UDP计算CheckSum
//填充字段值来自IP层
typedef struct tag_pseudo_header
{
u_int32_t source_address; //源IP地址
u_int32_t dest_address; //目的IP地址
u_int8_t placeholder; //必须置0,用于填充对齐
u_int8_t protocol; //8为协议号(IPPROTO_TCP=6,IPPROTO_UDP=17)
u_int16_t tcplength; //UDP/TCP头长度(不包含数据部分)
}PseudoHeader_S;
网络字节顺序与本地字节顺序之间的转换
本部分参考博客:https://blog.csdn.net/zhuguorong11/article/details/52300680
-
头文件:
<arpa/inet.h>
-
网络字节顺序NBO:按从高到低的顺序存储,在网络上使用统一的网络字节顺序,可以避免兼容性问题
-
主机字节顺序HBO:不同的机器HBO不相同,与CPU设计有关,数据的顺序是由cpu决定的,而与操作系统无关
-
函数原型:
//htonl()--"Host to Network Long" uint32_t htonl(uint32_t hostlong); //ntohl()--"Network to Host Long" uint32_t ntohl(uint32_t netlong); //htons()--"Host to Network Short" uint16_t htons(uint16_t hostshort); //ntohs()--"Network to Host Short" uint16_t ntohs(uint16_t netshort);
建立套接字
-
函数原型:
#include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol);
- domain:协议簇
- AF_UNIX(本机通信)
- AF_INET(TCP/IP – IPv4)
- AF_INET6(TCP/IP – IPv6)
- type
- SOCK_STREAM(TCP流)
- SOCK_DGRAM(UDP数据报)
- SOCK_RAW(原始套接字)
- domain:协议簇
系统调用
进程:
-
头文件:
<sys/types.h>
and<unistd.h>
-
函数原型1:
pid_t getpid(void)
:返回当前进程表示; -
函数原型2:
pid_t getppid(void)
:返回父进程标识; -
返回值:pid_t 定义如下,使用此标识可能是为了更好的移植性;不同的环境可能定义的类型不一样
sys/types.h:
typedef short pid_t; /* used for process ids */
获取时间
- 头文件:
<sys/time.h>
- 函数原型:
int gettimeofday(struct timeval *tv, struct timezone *tz)
- 返回值:tv返回目前的时间、tz所指的结构返回当时地区的信息;返回值 0 成功;-1失败,原因存于errno;
struct timeval{
long tv_sec; //秒
long tv_usec;//微秒
};
struct timezone{
int tz_minuteswest;//和greenwich时间查了多少分钟
int tz_dsttime; //DST 时间的修正方式
};
获得本地接口信息ioctl
ioctl 是设备驱动程序中设备控制接口函数,一个字符设备驱动通常会实现设备打开、关闭、读、写等功能,在一些需要细分的情境下,如果需要扩展新的功能,通常以增设 ioctl() 命令的方式实现。
- 头文件:
<sys/ioctl.h>
- 函数原型:
int ioctl(int fd, int cmd, [int *argc,int argv])
- 参数:fd为文件描述符,cmd交互协议,参数列表为可变参数arg,依据cmd指定长度和类型;
- 返回值:执行成功返回0,失败返回-1并设置全局变量errno值;常见的errno的值为ENOTTY(error not a typewriter)即第一个数fd指向的不是一个字符设备,不支持icotl操作,这时候应该检查前面的 open 函数是否出错或者设备路径是否正确。
相关cmd:数据类型为第三个参数类型
BUFFSIZ的值
定义:
stdio.h: #ifndef BUFSIZ
stdio.h: # define BUFSIZ _IO_BUFSIZ
libio.h: #define _IO_BUFSIZ _G_BUFSIZ
_G_config.h:#define _G_BUFSIZ 8192
使用的时候包含<stdio.h>
即可
获取接口信息
- 应用:
icotl(socket,SIOCGIFCONF,&ifconf)
; //获取接口清单 - ifreq用来配置ip地址,激活接口,配置MTU等接口信息的。其中包含了一个接口的名字和具体内容(是个共用体,有可能是IP地址,广播地址,子网掩码,MAC号,MTU或其他内容)。
- ifreq包含在ifconf结构中。而 ifconf结构通常是用来保存所有接口的信息的。
//ifconf 结构体 <net/if.h> 保存所有接口信息 用于检测机器接口的配置
struct ifconf
{
int ifc_len; /* size of buffer */
union
{
char *ifcu_buf; /* input from user->kernel*/
struct ifreq *ifcu_req; /* return from kernel->user*/
} ifc_ifcu;
};
#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */
#define ifc_req ifc_ifcu.ifcu_req /* array of structures *
//ifreq用来保存某个接口的信息
struct ifreq
{
#define IFHWADDRLEN 6
union{
char ifr_name[IFNAMSIZ]; /* if name 例如“en0"*/
}ifr_ifrn;
union {
struct sockaddr ifru_addr; /* 地址*/
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr; /*广播地址*/
struct sockaddr ifru_netmask; /*子网掩码*/
struct sockaddr ifru_hwaddr; /* MAC address */
short ifru_flags;
int ifru_ivalue;
int ifru_mtu; /*是指一种通信协议的某一层上面所能通过的最大数据包大小(以字节为单位)*/
struct ifmap ifru_map;
char ifru_slave[IFNAMSIZ]; /* Just fits the size */
char ifru_newname[IFNAMSIZ];
void __user * ifru_data; /*当前被使用的接口*/
struct if_settings ifru_settings;
} ifr_ifru;
};
#define ifr_name ifr_ifrn.ifrn_name /* interface name */
#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
#define ifr_addr ifr_ifru.ifru_addr /* address */
#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */
#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
#define ifr_flags ifr_ifru.ifru_flags /* flags */
#define ifr_metric ifr_ifru.ifru_ivalue /* metric */
#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
#define ifr_map ifr_ifru.ifru_map /* device map */
#define ifr_slave ifr_ifru.ifru_slave /* slave device */
#define ifr_data ifr_ifru.ifru_data /* for use by interface */
#define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */
#define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */
#define ifr_qlen ifr_ifru.ifru_ivalue /* Queue length */
#define ifr_newname ifr_ifru.ifru_newname /* New name */
#define ifr_settings ifr_ifru.ifru_settings /* Device/proto settings*/
设置套接口的选项
这一部分来源博客:晟夏的叶
-
函数原型和头文件:
#include <sys/types.h > #include <sys/socket.h> int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
-
参数说明:
sockfd
:标识一个套接口的描述字level
:选项定义的层次,支持SOL_SOCKET(套接字级别)、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6(IPPROTO_TCP 和 IPPROTO_IP代表两种不同的协议,分别代表IP协议族里面的TCP协议和IP协议)
optname
:需设置的选项,而有部分选项需在listen/connect调用前设置才有效,这部分选项如下:SO_DEBUG、SO_DONTROUTE、SO_KEEPALIVE、SO_LINGER、SO_OOBINLINE、SO_RCVBUF、SO_RCVLOWAT、SO_SNDBUF、SO_SNDLOWAT、TCP_MAXSEG、TCP_NODELAYoptval
:指针,指向存放选项值的缓冲区optlen
:optval缓冲区长度 -
设置socket的一些选项:
- 设置收发时限
int nNetTimeout=1000; // 1秒 // 发送时限 setsockopt(socket,SOL_S0CKET, SO_SNDTIMEO,(char *)&nNetTimeout,sizeof(int)); // 接收时限 setsockopt(socket,SOL_S0CKET, SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int));
- 强制关闭不经历TIME_WAIT
int reuse=0; setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const char*)& reuse,sizeof(int));
- 设置socket缓冲区大小,当收发数据较大时,而避免了send(),recv()不断的循环收发
// 接收缓冲区 int nRecvBuf=32*1024; // 设置为32K setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int)); // 发送缓冲区 int nSendBuf=32*1024; // 设置为32K setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));
- 设置不经过系统缓冲区到socket缓冲区
int nZero=0; setsockopt(socket,SOL_SOCKET,SO_SNDBUF,(char *)&nZero,sizeof(int));
-
同上在recv()完成上述功能(默认情况是将socket缓冲区的内容拷贝到系统缓冲区):
int nZero=0; setsockopt(socket,SOL_SOCKET,SO_RCVBUF,(char *)&nZero,sizeof(int));
-
一般在发送UDP数据报的时候,希望该socket发送的数据具有广播特性
int bBroadcast = 1; setsockopt(s, SOL_SOCKET, SO_BROADCAST, (const char*)&bBroadcast, sizeof(int));
- 设置存活检测
int opt = 1; if (setsockopt (m_nSock, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(int)) == -1) { return 0; }
- 延迟接收
实际上就是当接收到第一个数据之后,才会创建连接。对于像http这类非交互式的服务器,这个很有意义,可以防御空连接攻击。
int val = 5; setsockopt(fd, SOL_TCP, TCP_DEFER_ACCEPT, &val, sizeof(val));
打开这个功能后,内核在val时间之类还没有收到数据,不会继续唤醒进程,而是直接丢弃连接。
从三次握手上讲,就是设置这个状态之后,就算完成了三次握手,服务器socket状态也不是ESTABLISHED,而依然是 SYN_RCVD,不会去接收数据。
关于原始套接字
参考博客:https://blog.csdn.net/yanyiyyy/article/details/6566871
大致总结:使用原始套接字可以访问ICMP、IGMP等协议包,可以读写内核不处理的IP数据报,可以创建自定义的IP数据包首部,编写基于IP协议的通讯程序;
- 创建格式:
int sockfd;sockfd = socktet(AF_INET, SOCK_RAW, IPPROTO_ICMP)
- 注:须在root权限下
- 当需要编写自己的IP数据包首部时,可以在原始套接字上设置套接字选项IP_HDRINCL.在不设置这个选项的情况下,IP协议自动填充IP数据包的首部:
int on = 1;
if(setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0){
fprintf(stderr, "setsockopt IP_HDRINCL ERROR! /n");
exit(1);
}
- 如果没有设置IP_HDRINCL选项时,包内可写的内容为数据部分,内核将自动创建IP首部。如果设置了IP_HDRINCL选项,则包内要填充的内容为IP数据包和首部。
关于errno:
- errno,全局变量:记录系统的最后一次错误代码,为int型的值,由操作系统维护
- 输出:
printf("errno值:%d 错误提示信息:%s ",errno,sterror(errno))
; - 错误码对应的错误类型参考:“明明是悟空”的博客
perror
- 头文件:<stdlib.h>
- 函数体:
void perror(const char*s)
- perror ( )用 来 将 上 一 个 函 数 发 生 错 误 的 原 因 输 出 到 标 准 设备 (stderr) 。参数 s 所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno 的值来决定要输出的字符串。
创建线程
- 头文件:
<pthread.h>
- 函数原型:成功返回0,否则返回出错编号,
int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict_attr,void*(*start_rtn)(void*),void *restrict arg);
-
函数参数:
-
restrict tidp:指向线程标识符指针
typedef unsigned long int pthread_t; //用途:pthread_t用于声明线程ID。 sizeof (pthread_t) =4;
-
restrict_attr:用来设置线程属性
typedef struct { int detachstate; //线程的分离状态 int schedpolicy; //线程调度策略 struct sched_param schedparam; //线程的调度参数 int inheritsched; //线程的继承性 int scope; //线程的作用域 size_t guardsize; //线程栈末尾的警戒缓冲区大小 int stackaddr_set; void * stackaddr; //线程栈的位置 size_t stacksize; //线程栈的大小 }pthread_attr_t;
-
start_rtn:线程运行函数的地址
-
restrict arg:运行函数的参数
-
-
注:在编译时注意加上-lpthread参数,以调用静态链接库。因为pthread并非Linux系统的默认库。
内存拷贝函数
- 函数原型:
void *memcpy(void *destin, void *source, unsigned n)
- 功能:从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源source中拷贝n个字节到目标destin中。
sendto 和 recvfrom
sendto和recvfrom一般用于UDP协议中,但是如果在TCP中connect函数调用后也可以用.
- 利用数据报方式进行数据传输
- 在无连接的数据报socket方式下,由于本地socket并没有与远端机器连接,所以在发送数据时应指明目的地址。
- 头文件:
<sys/types.h>
和<sys/socket.h>
- 返回值:如果成功则返回实际传送出去/接收到的字符数,失败则返回-1,错误原因存于errno中
sendto:
-
函数原型:
int sendto(int sockfd, const void *msg,int len, unsigned int flags, const struct sockaddr *to, int tolen);
-
参数:
- sockfd:套接字
- msg:消息数据报
- len:数据报长度
- flags:一般为0
- to:目的地址,sockaddr类型(协议族、端口号、IP地址)
- tolen:对方地址长度,一般为:
sizeof(struct sockaddr_in)
recvfrom:
-
函数原型:
int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int *fromlen);
-
参数同上
fflush方法
参考博客:NUAA、无痕
-
功 能: 清除读写缓冲区,需要立即把输出缓冲区的数据进行物理写入时
-
头文件:
<stdio.h>
-
原型:
int fflush(FILE *stream)
其中stream是要冲洗的流 -
fflush(stdin)刷新标准输入缓冲区,把输入缓冲区里的东西丢弃[非标准],一般用不到。
-
fflush(stdout)刷新标准输出缓冲区,把输出缓冲区里的东西打印到标准输出设备上
-
printf("字符串");后面加fflush(stdout);可提高打印效率!
Linux的sleep()、usleep()、nanosleep()区别与联系
参考博客:专注就可以深
sleep:
- 头文件:
<unistd.h>
- 函数原型:
unsigned int sleep(unsigned int seconds);
- 特点:非系统调用,在库函数中实现,通过alarm来设定报警时间,使用
sigsuspend()
将进程挂起在信号SIGALARM上。sleep()精确到秒级,会令目前的进程暂停,直到达到参数seconds所指定的时间,或是被信号所中断。 - 返回值:若进程暂停到参数seconds 所指定的时间,成功则返回0,若有信号中断则返回剩余微秒数。
usleep:
- 头文件:
<unistd.h>
- 函数原型:
unsigned int usleep(unsigned int useconds);
- 特点:时间以微秒为单位;
- 返回值:若进程暂停到参数seconds 所指定的时间,成功则返回0,若有信号中断则返回剩余微秒数。
nanosleep:
-
头文件:
<time.h>
-
函数原型:
struct timespec { time_t tv_sec; /* 秒seconds */ long tv_nsec; /* 纳秒nanoseconds */ }; int nanosleep(const struct timespec *req, struct timespec *rem)
-
这个函数功能是暂停某个进程直到你规定的时间后恢复,参数req就是你要暂停的时间,其中req->tv_sec是以秒为单位,而tv_nsec以毫微秒为单位(10的-9次方秒)。由于调用nanosleep是是进程进入TASK_INTERRUPTIBLE,这种状态是会相应信号而进入TASK_RUNNING状态的,这就意味着有可能会没有等到你规定的时间就因为其它信号而唤醒。
-
返回值: 若进程暂停到参数
*req
所指定的时间,成功则返回0,若有信号中断则返回-1,并且将剩余微秒数记录在*rem
中。
命令行选项函数gotopt()
-
函数原型:
int getopt(int argc, char * const argv[], const char *optstring);
-
说明:getopt是用来解析命令行选项参数的,但是只能解析短选项: -d 100,不能解析长选项:--prefix
-
参数:
argc
:main()
函数传递过来的参数的个数argv
:main()
函数传递过来的参数的字符串指针数组optstring
:选项字符串,告知getopt()
可以处理哪个选项以及哪个选项需要参数
-
返回值:如果选项成功找到,返回选项字母;如果所有命令行选项都解析完毕,返回 -1;如果遇到选项字符不在
optstring
中,返回字符 '?';如果遇到丢失参数,那么返回值依赖于optstring
中第一个字符,如果第一个字符是 ':' 则返回':',否则返回'?'并提示出错误信息。 -
optstring
在传入之后,getopt
函数将依次检查命令行是否指定了-a, -b, -c
(这需要多次调用getopt
函数,直到其返回-1),当检查到上面某一个参数被指定时,函数会返回被指定的参数名称(即该字母)
socket
-
函数原型:
int socket(int domain, int type, int protocol);
-
参数:
-
domain:协议域,协议簇(family)
名称 目的 AF_INET IPv4网络通信 AF_INET6 IPv6网络通信 AF_PACKET 链路层通信 AF_UNIX, AF_LOCAL 本地通信 -
type:
type 说明 SOCK_STREAM(默认) 面向字节流套接字,基于TCP SOCK_DGRAM 数据报套接字,基于UDP SOCK_SEQPACKET 有序分组套接字 SOCK_RAW 原始套接字 -
protocol:通常为0,表示选择当前family和type组合下protocol的系统默认值
IPPROTO_TCP IPPTOTO_UDP IPPROTO_SCTP IPPROTO_TIPCTCP TCP传输协议 UDP传输协议 STCP传输协议 TIPC传输协议
-
数据格式
数据与填充拆分出来第一部分都是网络层IP数据报,IP首部:首部格式:
IP首部的数据部分拆出来可能是:传输层UDP、TCP、ICMP、IGMP。
UDP:
TCP:
ICMP:
ICMP是在IP数据报的内部被传输的,紧跟着IP报文的首部(如果IP首部有可选部分,则紧跟着可选部分):