网络编程

地址相关结构体

结构 场景 注意
struct sockaddr {
sa_family_t sa_family; // 地址族,如 AF_INET、AF_INET6
char sa_data[14]; // 地址数据
};
通用地址 不能直接用于bind,需要转为具体ipv4/6
struct sockaddr_in {
sa_family_t sin_family; // AF_INET
in_port_t sin_port; // 端口号(16 位),需要转换
struct in_addr sin_addr; // IPv4 地址(32位),需转换
};
ipv4地址 - 端口号和ip必须经过转换才能设置。htons和inet_pton
- 只能用于IPV4
struct sockaddr_in6 {
sa_family_t sin6_family; // AF_INET6
in_port_t sin6_port; // 端口号(16 位),需要转换
struct in6_addr sin6_addr; // IPv6 地址
};
ipv6地址
struct addrinfo {
int ai_flags; // 选项,如 AI_PASSIVE(用于 bind()
int ai_family; // 地址族(AF_INET / AF_INET6 / AF_UNSPEC)
int ai_socktype; // 套接字类型(SOCK_STREAM / SOCK_DGRAM)
int ai_protocol; // 协议(通常为 0)
size_t ai_addrlen; // 地址结构体大小
struct sockaddr *ai_addr; // 指向 sockaddr 结构体
char *ai_canonname; // 规范主机名(可选)
struct addrinfo *ai_next; // 指向下一个 addrinfo
};
解析域名返回地址表,包含IPV4,IPV6。通常,用这些地址建立socket连接。 - 与sockaddr不同,可以直接进行兼容编程。
- 用于getaddrinfo()解析主机,获取ip
struct sockaddr_storage 给足够大的空间,IPV4/6都可以通过这个存储。通常,用这个存储accept等得到的地址

套接字函数

函数 含义 注意
int socket(int domain, int type, int protocol);
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int listen(int sockfd, int backlog);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
UDP 发送数据
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
UDP 接收数据
close(sockfd);

其他辅助函数

函数 含义 注意
inet_pton(AF_INET, “127.0.0.1”, &addr.sin_addr); IP 地址转换:字符串 -> 二进制
inet_ntop(AF_INET, &addr.sin_addr, ip_str, sizeof(ip_str)); IP 地址转换:二进制 -> 字符串
uint32_t htonl(uint32_t hostlong); 字节序转换: 主机 -> 网络字节序(32 位)
uint16_t htons(uint16_t hostshort); 字节序转换:主机 -> 网络字节序(16 位)
uint32_t ntohl(uint32_t netlong); 字节序转换:网络 -> 主机字节序(32 位)
uint16_t ntohs(uint16_t netshort); 字节序转换:网络 -> 主机字节序(16 位)

未归:

  • getaddrinfo():实现具体依赖于网络库,所以在netdb.h中只是extern,并没有具体实现,真正的实现在glibc中,需要编译连接

  • SO_REUSEADDR 套接字选项:快速在同一端口重启。

TCP连接关闭,会进入TIME_WAIT状态,等待确保所有数据能够处理。 在这个状态下,端口不能重新绑定,直到连接上没有数据包流动。

默认情况下,TIME_WAIT会持续2-4分钟。取决于操作系统配置。

  • TCP_NODELAY:Nagle算法会将小的数据包合成大的再发,等待缓冲区满了发。 启用不能保证实时性,
  • TCP Keep-Alive :会在连接空闲时候发生保活包检测是否连接有效,如果指定时间内没有响应就断开
    • TCP_KEEPIDLE:连接空闲多长时间后开始发送保活探测包(单位:秒)。
    • TCP_KEEPINTVL:保活探测包之间的时间间隔(单位:秒)。
    • TCP_KEEPCNT:在认为连接失效之前,最多发送多少个保活探测包。