套接字编程基础
IPv4套接字地址结构
/* <netinet/in.h> */
struct in_addr {
in_addr_t s_addr; /* 32-bit IPv4 address */
/* network byte ordered */
}
struct sockaddr_in {
uint8_t sin_len; /* length of structure (16-bit) */
sa_family_t sin_family; /* AF_INET (16-bit) */
in_port_t sin_port; /* 16-bit TCP or UDP port number */
/* network byte ordered */
struct in_addr sin_addr;
char sin_zero[8]; /* unused */
}
通用套接字地址结构
/* <sys/socket.h> */
struct sockaddr {
uint8_t sa_len; /* length of structure (16-bit) */
sa_family_t sa_family; /* address family: AF_xxx value */
char sa_data[14]; /* protocol-specific address */
}
IPv6套接字地址结构
/* netinet/in.h */
struct in6_addr {
uint8_t s6_addr[16]; /* 128-bit IPv6 address */
}
struct sockaddr_in6 {
uint8_t sin6_len; /* length of this struct (28) */
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* transport layer port */
uint32_t sin6_flowinfo; /* flow information, undefined */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id;
}
新的通用套接字地址结构
struct sockaddr_storage {
uint8_t ss_len;
sa_family_t ss_family;
}
字节序(大小端)
非常喜欢UNP对于大小端字节序的解释,清晰明了。原文是这样描述的:
考虑一个16位整数,它由2个字节组成,内存中存储这两个字节有两种方法:一种是将低序字节存储在起始地址,这称为小端(litttle-endian)字节序;另一种方法是将高序字节存储在起始地址,这称为大端(big-endian)字节序。
网络字节序默认是大端字节序。
字节序转换函数
#include <netinet/in.h>
uint16_t htons(uint16_t host16bitvalue);
uint32_t htonl(uint32_t host32bitvalue);
uint16_t ntohs(uint16_t net16bitvalue);
uint32_t ntohl(uint32_t net32bitvalue);
地址转换函数
#include <arpa/inet.h>
/* 仅适用于IPv4 */
int inet_aton(const char *strptr, struct in_addr *addrptr);
in_addr_t inet_addr(const char *strptr);
char *inet_ntoa(struct in_addr inaddr);
/* 对于IPv4地址和IPv6地址都适用 */
int inet_pton(int family, const char *strptr, void *addrptr);
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
基本套接字函数
#include <sys/socket.h>
/* 返回:若成功则为非负描述符,若出错则为-1 */
int socket(int family, int type, int protocol);
int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);
int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
int listen(int sockfd, int backlog);
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
/* 返回与套接字关联的本地协议地址 */
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);
/* 返回与套接字管理的外地协议地址 */
int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);
#include <unistd.h>
pid_t fork(void);
int close(int sockfd);
参考
《UNIX网络编程 - 卷1:套接字联网API (第3版)》