前言:算是开了「网络编程」的坑,以后的方向是做安全,到毕业主要钻研两个方向——计算机网络和操作系统,加油。我正在读的书在这里,博客大部分内容也是来自这里

0X00 与网络编程相关的数据结构
- socket 描述符
与普通的文件描述符一样都是 int 类型
- addrinfo struct
struct addrinfo
{
int ai_flags; // AI_PASSIVE, AI_CANONNAME, etc.
int ai_family; // AF_INET, AF_INET6, AF_UNSPEC
int ai_socktype; // SOCK_STREAM, SOCK_DGRAM
int ai_protocol; // use 0 for "any"
size_t ai_addrlen; // size of ai_addr in bytes
struct sockaddr *ai_addr; // struct sockaddr_in or _in6
char *ai_canonname; // full canonical hostname
struct addrinfo *ai_next; // linked list, next node
};
一般通过 getaddrinfo() 得到 addrinfo,其中:
ai 就是 addrinfo 的意思。ai_family 用来设置 ipv4,ipv6,还是都可以。socket 有多种类型 ai_socktype 就是用来设置类型。使用 getaddrinfo() 可能有多个结果,所以它可能有一串 addrinfo , ai_next 用来指向下一个 addrinfo
- sockaddr
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
上面还有一个 sockaddr,sockaddr 的结构如上。sa_data 包含 socket 的目标地址和端口号。
但是这样写太麻烦了,端口号和地址写在一起了,又提出了一个可以兼容这个结构的 sockaddr_in(都是 16 字节)
- sockaddr_in
// ipv4
struct sockaddr_in {
short int sin_family; // Address family, AF_INET
unsigned short int sin_port; // Port number
struct in_addr sin_addr; // Internet address
unsigned char sin_zero[8]; // Same size as struct sockaddr
};
在这个结构中,sin_zero 是用来填充大小的,为了和 sockaddr 大小一样,初始化的时候使用 memset() 全部设置为 0,还有一个 in_addr 结构
- in_addr
// ipv4
struct in_addr {
uint32_t s_addr; // that's a 32-bit int (4 bytes)
};
- 我们再来看看 ipv6
truct sockaddr_in6 {
u_int16_t sin6_family; // address family, AF_INET6
u_int16_t sin6_port; // port number, Network Byte Order
u_int32_t sin6_flowinfo; // IPv6 flow information
struct in6_addr sin6_addr; // IPv6 address
u_int32_t sin6_scope_id; // Scope ID
};
struct in6_addr {
unsigned char s6_addr[16]; // IPv6 address
};
这个数据结构我没怎么弄懂,先放着吧,等我学深入了就好了
struct sockaddr_storage {
sa_family_t ss_family; // address family
// all this is padding, implementation specific, ignore it:
char __ss_pad1[_SS_PAD1SIZE];
int64_t __ss_align;
char __ss_pad2[_SS_PAD2SIZE];
};
- inet_ntoa() 用法
struct sockaddr_in sa; // IPv4
struct sockaddr_in6 sa6; // IPv6
inet_pton(AF_INET, "10.12.110.57", &(sa.sin_addr)); // IPv4
inet_pton(AF_INET6, "2001:db8:63b3:1::3490", &(sa6.sin6_addr)); // IPv6
用法如下:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main()
{
// IPv4:
char ip4[INET_ADDRSTRLEN];
struct sockaddr_in sa;
// space to hold the IPv4 string
// pretend this is loaded with something
inet_ntop(AF_INET, &(sa.sin_addr), ip4, INET_ADDRSTRLEN);
printf("The IPv4 address is: %s\n", ip4);
// IPv6:
char ip6[INET6_ADDRSTRLEN]; // space to hold the IPv6 string
struct sockaddr_in6 sa6;
// pretend this is loaded with something
inet_ntop(AF_INET6, &(sa6.sin6_addr), ip6, INET6_ADDRSTRLEN);
printf("The address is: %s\n", ip6);
return 0;
}
将 sockaddr_in 转换成字符串

下一篇文章将介绍常见 API