目录
1.套接字地址介绍
1.1 通用套接字地址
#include <sys/socket.h>
struct sockaddr {
unsigned short sa_family;
char sa_data[14];
};
图 1
解析:
sa_family:2字节地址族
sa_data:14字节填充
作用:作为套接字函数参数使用
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
1.2 新的通用套接字地址
#include <bits/socket.h>
struct sockaddr_storage {
unsignedshort ss_family;
char __ss_padding[118];
unsigned long __ss_align;
};
图 2
解析:
sa_family:2字节地址族
__ss_padding:118字节填充
__ss_align:8字节对齐字段
作用:
作为内存块使用,转换成其他套接字地址结构使用
1.3 IPv4套接字地址
#include <netinet/in.h>
struct sockaddr_in {
unsigned short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
struct in_addr {
unsigned int s_addr;
};
图 3
解析:
sin_family:2字节地址族,AF_INET
sin_port:2字节端口号,大端类型,可用htons函数转换为大端类型
sin_addr:4字节IP地址,大端类型,可用inet_addr函数转换字符IP地址为整型IP地址
sin_zero:8字节填充
作用:IPv4 TCP和UDP网路编程套接字地址
1.4 数据链路层套接字地址
#include <linux/if_packet.h>
struct sockaddr_ll {
unsigned short sll_family;
unsigned short sll_protocol;
int sll_ifindex;
unsigned short sll_hatype;
unsigned char sll_pkttype;
unsigned char sll_halen;
unsigned char sll_addr[8];
};
图4
解析:
sll_family:2字节地址族,PF_PACKET
ssl_protocol:2字节上层协议(以太网类型),大端类型,如IPPROTO_IP
sll_ifindex:4字节网络接口索引号,可通过if_nametoindex函数通过网口名获取
sll_hatype:2字节ARP硬件地址类型,如ARPHRD_ETHER
sll_pkttype:1字节分组类型,如:PACKET_OTHERHOST
sll_halen:1字节数据链路层地址长度
sll_addr:8字节数据链路层地址
作用:
数据链路层套接字编程地址
1.5 域套接字地址
#include <linux/un.h>
struct sockaddr_un {
unsigned short t sun_family;
char sun_path[108];
};
图5
解析:
sun_family:2字节地址族,AF_UNIX
sun_path:最大108字节系统路径,如:/tmp/test,由用户自己定义
作用:
域套接字编程使用
2.套接字地址内存对象模型
图6:套接字地址内存对象模型
3.套接字地址关系
3.1 IPv4套接字编程
//申请IPv4套接字地址内存空间
struct sockaddr_storage addr;
//struct sockaddr_storage转换为struct sockaddr_in
struct sockaddr_in *in_addr = (struct sockaddr_in * )&addr;
in_addr->sin_family = AF_INET;
in_addr->sin_port = htons(1234);
in_addr->sin_addr.s_addr = inet_addr("192.168.1.2");
//struct sockaddr_in转换为struct sockaddr
bind(..., (struct sockaddr *)&in_addr, ...);
connect(..., (struct sockaddr *)&in_addr, ...);
......
3.2 数据链路套接字编程
//申请数据链路层套接字地址内存空间
struct sockaddr_storage addr;
//struct sockaddr_storage转换为struct sockaddr_ll
struct sockaddr_ll *ll_addr = (struct sockaddr_ll *)&addr;
ll_addr->sll_family = PF_PACKET;
ll_addr->sll_protocol = htons(ETH_P_IP);
ll_addr->sll_ifindex = 2;
ll_addr->sll_hatype = ARPHRD_ETHER;
ll_addr->sll_pkttype = PACKET_OTHERHOST;
ll_addr->sll_halen = ETH_ALEN;
uint8_t mac[ETH_ALEN] = {0xf4,0x83,0xcd,0xa8,0xb3,0xcd};
memcpy(ll_addr.sll_addr, mac, ETH_ALEN);
//struct sockaddr_ll转换为struct sockaddr
bind(..., (struct sockaddr *)&ll_addr, ...);
connect(..., (struct sockaddr *)&ll_addr,...);
......
3.2 域套接字编程
//申请域套接字地址内存空间
struct sockaddr_storage addr;
//struct sockaddr_storage转换为struct sockaddr_un
struct sockaddr_un *un_addr = (struct sockaddr_un *)&addr;
un_addr->sun_family = AF_UNIX;
memcpy(&un_addr->sun_path, "/tmp/test", sizeof("/tmp/test"));
//struct sockaddr_un转换为struct sockaddr
bind(..., (struct sockaddr *)&un_addr, ...);
connect(..., (struct sockaddr *)&un_addr, ...);