socket编程
OSI模型如下:

socket编程参数区别
网卡对数据帧进行硬过滤,根据网卡的模式不同采取不同的操作:
如果设置了混杂模式,则不做任何过滤直接交给下一层;
否则非本机mac或者广播mac的会被直接丢弃。
套接字创建方式
发送接收IP层数据包
socket(AF_INET, SOCK_RAW, IPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP)
该套接字可以接收协议类型为tcp、udp、icmp等发往本机的ip数据包
不能接收非发往本机ip的数据包,因为IP地址会过滤掉丢弃非本机IP的数据包
不能接收从本机发出去的数据
发送:需要自己组UDP/TCP头,IP和以太网头部由内核完成
即用户需要组装
TCP/UDP 头 + data注意: 想自己也想亲自处理IP头,则需要
IP_HDRINCL的socket选项。如下 :int flag = 1; setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &flag, sizeof(int));
即用户需要组装
IP头 + TCP/UDP 头 + data注意: 即使是这种情况,在我们发送IP包的时候,也不是填充ip头的所有字段,而是应该将ip头的id(identification)字段设置为0。表示让内核来处理这个字段。同时,内核还帮你完成ip头的校验和的计算,并随后填充check字段。
第三个参数如果是 IPPROTO_TCP等非0非255 的数据,内核查看是否是自己填的IPPROTO_TCP等协议,如果是交给这个socket处理。
第三个参数如果是 IPPROTO_RAW(255),这个 socket只能用来发送IP包,而不能接收任何数据。发送的数据需要自己填充IP包头,并且自己计算校验和。谨慎使用。
发送接收以太网数据帧
socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))
能接收发往本机mac的数据帧
能接收从本机发出去的数据帧,需要第三个参数为ETH_P_ALL
能接收非发往本地mac的数据帧:网卡需要设置为混杂模式 promisc
协议类型就四种
ETH_P_IP 0x800 :只接收发往本机mac的ip类型的数据帧
ETH_P_ARP 0x806 :只接受发往本机mac的arp类型的数据帧
ETH_P_RARP 0x8035 :只接受发往本机mac的rarp类型的数据帧
ETH_P_ALL 0x3 :接收发往本机mac的所有类型的数据帧, 接收从本机发出的所有类型的数据帧。(混杂模式打开的情况下,会接收到非发往本地mac的数据帧)
总结
类型 |
SOCK_RAW |
SOCK_DGRAM |
SOCK_STREAM |
|---|---|---|---|
AF_INET |
接收:IP报文头 发送:UDP/TCP头开始(**注意:**使用IP_HDRINCL选项可以从IP报文头开始) |
接收:UDP应用层数据 发送:UDP应用层数据 |
接收:TCP应用层数据 发送:TCP应用层数据 |
PF_PACKET |
接收:以太网报文头 发送:以太网头开始 |
接收:IP报文头 发送:IP报文头开始 |
使用技巧
调整socket接收缓存大小
通过getsockopt可以获得socket的当前接收和发送缓存的大小,我的程序中获取出来的发送和接收缓存都是262144字节(256KB)。采用默认的接收缓存大小的测试结果中可能会出现文件大小偏小。
使用setsockopt设置接收缓存的大小为2x1024x1024字节(2M,已经很大了),然后再多次测试,基本上没有结果偏小的情况,但是有时会出现结果偏大(重传以及选择性重传过滤不完全,内容有交叠导致的)
设置混杂模式
发向所有机器的广播数据帧。如果网卡要接收所有通过它的数据,而不管是不是发给它的,就必须把网卡置于混杂模式。
struct ifreq ethreq;
strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);
ethreq.ifr_flags |= IFF_PROMISC;
ioctl(sock, SIOCGIFFLAGS, ðreq);
协议族和地址族区别

协议族
协议族就是不同协议的集合,在Linux中,用宏来表示不同的协议族,这个宏的形式是PF开头,比如IPv4协议族为PF_INET,PF的意思是PROTOCOL FAMILY,这些宏定义在/usr/include/bits/socket.h中
/* Protocol families. */
#define PF_UNSPEC 0 /* Unspecified. */
#define PF_LOCAL 1 /* Local to host (pipes and file-domain). */
#define PF_UNIX PF_LOCAL /* POSIX name for PF_LOCAL. */
#define PF_FILE PF_LOCAL /* Another non-standard name for PF_LOCAL. */
#define PF_INET 2 /* IP protocol family. */
#define PF_AX25 3 /* Amateur Radio AX.25. */
#define PF_IPX 4 /* Novell Internet Protocol. */
#define PF_APPLETALK 5 /* Appletalk DDP. */
#define PF_NETROM 6 /* Amateur radio NetROM. */
#define PF_BRIDGE 7 /* Multiprotocol bridge. */
#define PF_ATMPVC 8 /* ATM PVCs. */
#define PF_X25 9 /* Reserved for X.25 project. */
#define PF_INET6 10 /* IP version 6. */
#define PF_ROSE 11 /* Amateur Radio X.25 PLP. */
#define PF_DECnet 12 /* Reserved for DECnet project. */
#define PF_NETBEUI 13 /* Reserved for 802.2LLC project. */
#define PF_SECURITY 14 /* Security callback pseudo AF. */
#define PF_KEY 15 /* PF_KEY key management API. */
#define PF_NETLINK 16
#define PF_ROUTE PF_NETLINK /* Alias to emulate 4.4BSD. */
#define PF_PACKET 17 /* Packet family. */
#define PF_ASH 18 /* Ash. */
#define PF_ECONET 19 /* Acorn Econet. */
#define PF_ATMSVC 20 /* ATM SVCs. */
#define PF_RDS 21 /* RDS sockets. */
#define PF_SNA 22 /* Linux SNA Project */
#define PF_IRDA 23 /* IRDA sockets. */
#define PF_PPPOX 24 /* PPPoX sockets. */
#define PF_WANPIPE 25 /* Wanpipe API sockets. */
#define PF_LLC 26 /* Linux LLC. */
#define PF_IB 27 /* Native InfiniBand address. */
#define PF_MPLS 28 /* MPLS. */
#define PF_CAN 29 /* Controller Area Network. */
#define PF_TIPC 30 /* TIPC sockets. */
#define PF_BLUETOOTH 31 /* Bluetooth sockets. */
#define PF_IUCV 32 /* IUCV sockets. */
#define PF_RXRPC 33 /* RxRPC sockets. */
#define PF_ISDN 34 /* mISDN sockets. */
#define PF_PHONET 35 /* Phonet sockets. */
#define PF_IEEE802154 36 /* IEEE 802.15.4 sockets. */
#define PF_CAIF 37 /* CAIF sockets. */
#define PF_ALG 38 /* Algorithm sockets. */
#define PF_NFC 39 /* NFC sockets. */
#define PF_VSOCK 40 /* vSockets. */
#define PF_KCM 41 /* Kernel Connection Multiplexor. */
#define PF_QIPCRTR 42 /* Qualcomm IPC Router. */
#define PF_SMC 43 /* SMC sockets. */
#define PF_MAX 44 /* For now.. */
地址族
地址族就是一个协议族所使用的地址集合,也是用宏来表示不同的地址族,这个宏的形式是AF开头,比如IP地址族为AF_INET,AF的意思是ADDRESS FAMILY,这些宏定义在/usr/include/bits/socket.h中
/* Address families. */
#define AF_UNSPEC PF_UNSPEC
#define AF_LOCAL PF_LOCAL
#define AF_UNIX PF_UNIX
#define AF_FILE PF_FILE
#define AF_INET PF_INET
#define AF_AX25 PF_AX25
#define AF_IPX PF_IPX
#define AF_APPLETALK PF_APPLETALK
#define AF_NETROM PF_NETROM
#define AF_BRIDGE PF_BRIDGE
#define AF_ATMPVC PF_ATMPVC
#define AF_X25 PF_X25
#define AF_INET6 PF_INET6
#define AF_ROSE PF_ROSE
#define AF_DECnet PF_DECnet
#define AF_NETBEUI PF_NETBEUI
#define AF_SECURITY PF_SECURITY
#define AF_KEY PF_KEY
#define AF_NETLINK PF_NETLINK
#define AF_ROUTE PF_ROUTE
#define AF_PACKET PF_PACKET
#define AF_ASH PF_ASH
#define AF_ECONET PF_ECONET
#define AF_ATMSVC PF_ATMSVC
#define AF_RDS PF_RDS
#define AF_SNA PF_SNA
#define AF_IRDA PF_IRDA
#define AF_PPPOX PF_PPPOX
#define AF_WANPIPE PF_WANPIPE
#define AF_LLC PF_LLC
#define AF_IB PF_IB
#define AF_MPLS PF_MPLS
#define AF_CAN PF_CAN
#define AF_TIPC PF_TIPC
#define AF_BLUETOOTH PF_BLUETOOTH
#define AF_IUCV PF_IUCV
#define AF_RXRPC PF_RXRPC
#define AF_ISDN PF_ISDN
#define AF_PHONET PF_PHONET
#define AF_IEEE802154 PF_IEEE802154
#define AF_CAIF PF_CAIF
#define AF_ALG PF_ALG
#define AF_NFC PF_NFC
#define AF_VSOCK PF_VSOCK
#define AF_KCM PF_KCM
#define AF_QIPCRTR PF_QIPCRTR
#define AF_SMC PF_SMC
#define AF_MAX PF_MAX
区别
地址族和协议族其实是一样的,值也一样,都是用来识别不同协议的,为什么要搞两套东西呢?这是因为之前UNIX有两种风格系统:BSD系统和POSIX系统:
对于BSD系统,一直用的是AF;
对于POSIX系统,一直用的是PF
Linux作为后起之秀,为了兼容,所以两种都支持。
BSD系统和POSIX系统简介
POSIX系统:Bell实验室的Ken Thompson和Dennis Richie一起发明了Unix系统,随着Unix系统的成长,后来占领了市场,公司多了,懂得的人也多了,就分家了。后来Unix太多太乱,大家编程接口甚至命令都不一样了,为了规范大家的使用和开发,就出现了POSIX标准。典型的POSIX标准的UNIX实现有Solaris和AIX等。
BSD系统:BSD代表伯克利软件条件,是20世界70年代,加州大学伯克利分校对贝尔实验室UNIX进行了一系列修改后的版本,它最终发展成了一个完整的操作系统,有着自己的一套标准。现在有多个不同的BSD分支。今天,BSD并不特指任何一个BSD衍生版本,而是类UNIX操作系统的一个分支总称。典型代表是FreeBSD、NetBSD、OpenBSD等。