🤖 AI文章摘要 qwen-turbo-latest
加载中...

1. sys/socket.h

1.1 数据结构

  //sockaddr是一个bind默认接受的地址结构体,使用其他地址结构需要强转
struct sockaddr {  
	sa_family_t sa_family;  
	char        sa_data[14];  
}
  
  //sockaddr_un记录本地套接字地址,本地套接字和IP套接字的区别只有地址的不同
struct sockaddr_un {  
	__kernel_sa_family_t sun_family; /* AF_UNIX 协议簇,本地通信使用AF_UNIX*/  
	char sun_path[UNIX_PATH_MAX];   /* pathname socket伪文件名,若文件不存在会自动创建*/  
};
  
  //sockaddr_in记录IPv4套接字地址
struct sockaddr_in {  
 __kernel_sa_family_t  sin_family;     /* Address family 协议粗,IPv4通信使用AF_INET*/  
 __be16                sin_port;       /* Port number 大端存储的short变量,表示一个端口. 需要使用htons将小端数转为大端*/  

/*struct in_addr {__be32 s_addr;}*/
 struct in_addr        sin_addr;       /* Internet address 大端存储的的int变量,表示一个IPv4地址,需要使用htonl将小端数转为大端 */  
  
 /* Pad to size of `struct sockaddr'. 一个数组*/  
 unsigned char         __pad[__SOCK_SIZE__ - sizeof(short int) -  sizeof(unsigned short int) - sizeof(struct in_addr)];  
};


//sockaddr_in6记录v6套接字地址
struct sockaddr_in6 {  
	unsigned short int      sin6_family;    /* AF_INET6 协议簇,IPv6通信使用AF_INET6*/  
	__be16                  sin6_port;      /* Transport layer port # 大端存储的short变量,表示一个端口*/  
	__be32                  sin6_flowinfo;  /* IPv6 flow information */  
/*
struct in6_addr {  
	union {  
	__u8            u6_addr8[16];  
	#if __UAPI_DEF_IN6_ADDR_ALT  
	__be16          u6_addr16[8];  
	__be32          u6_addr32[4];  
	#endif
}
*/
	struct in6_addr         sin6_addr;      /* IPv6 address 大端存储的128位整形变量,表示一个地址*/  
	__u32                   sin6_scope_id;  /* scope id (new in RFC2553) */  
};



//arpa/inet.h是配合IP协议使用的一个工具库
uint32_t htonl(uint32_t hostlong)	//小端长整形转大端长整形
uint16_t htons(uint16_t hostshort)	//小端短整形转大端短整形
uint32_t ntohl(uint32_t netlong)	//大端长整形转小端长整形
uint16_t ntohs(uint16_t netshort)	//大端短整形转小端短整形
int inet_pton(						//点分十进制IP地址转大端int整形,使用dst传出
	int af, 
	const char *src, 
	void *dst)	
const char *inet_ntop(				//大端int整形转点分十进制字符串
	int af, 
	const void *src, 
	char *dst, 
	socklen_t size)
  

待验证条目:

  • socket的半关闭shutdown close的区别
  • socket的状态
    socket注意事项:
  • read未读取足够的数据时阻塞
  • write缓存已满时阻塞

1.2 函数

  int socket(							//获取socket文件描述符,返回socket文件描述符
	int domain,						//IPv4使用AF_INTE, IPv6使用AF_INET6
	int type, 						//SOCK_STREAM    SOCK_DGRAM   SOCK_RAW
	int protocol)					//0

int bind(							//将socket绑定到本地地址, 服务器需要调用该函数, 客户端可以不调用connect时会隐式调用, 总之一个socket必须绑定一个地址. 成功返回0, 失败返回-1设置errno
	int sockfd, 					//socket文件描述符
	const struct sockaddr *addr, 	//sockaddr结构体指针
	socklen_t addrlen)				//addr结构体的长度

int listen(							//将套接字设为监听状态
	int sockfd, 					//socket文件描述符
	int backlog): 					//同时连接到该socket的最大连接数

int accept(							//阻塞等待客户端的连接请求, 套接字必须为Listen状态。返回与客户端通信的socket文件描述符
	int sockfd, 					//socket文件描述符	
	struct sockaddr *restrict addr,	//sockaddr结构体指针(客户端地址)
	socklen_t *restrict addrlen)	//addr结构体长度(函数内部可能修改该值所以传指针) 

int connect(						//连接,返回与服务器通信的socket文件描述符
	int sockfd, 					//socket文件描述符
	const struct sockaddr *addr, 	//sockaddr结构体指针
	socklen_t addrlen)				//addr结构体长度

ssize_t send(
	int sockfd, 
	const 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)
ssize_t recvfrom(
	int sockfd, void *buf, size_t len, 
	int flags, 
	struct sockaddr *src_addr, 
	socklen_t *addrlen)
ssize_t recv(
	int sockfd, 
	void *buf, 
	size_t len, 
	int flags)
int getsockopt(
	int sockfd, int level, 
	int optname,  
	void *optval, 
	socklen_t *optlen);  
int setsockopt(			//需要在bind函数前调用
	int sockfd, 
	int level, 
	int optname,  
	const void *optval, 
	socklen_t optlen)
- 
  

2. sys/select.h

2.1 数据结构

2.2 成员函数

  int select(
	int nfds, 
	fd_set *readfds, 
	fd_set *writefds, 
	fd_set *exceptfds, 
	struct timeval *timeout)

void FD_CLR(int fd, fd_set *set);  
int  FD_ISSET(int fd, fd_set *set);  
void FD_SET(int fd, fd_set *set);  
void FD_ZERO(fd_set *set);
  

3. poll.h

3.1 数据结构

3.2 成员函数

  int poll(
	struct pollfd *fds, 
	nfds_t nfds, 
	int timeout);
  

4. sys/epoll.h

4.1 数据结构

  struct epoll_event {  
	uint32_t     events;	/* Epoll events 是一个位图, EPOLLIN: 当读缓冲区有数据时返回; EPOLLOUT: 当写缓冲区可写时返回 EPOLLET:设置边缘触发. 设置边缘触发后,EPOLLIN表现为客户端发数据才触发,EPOLLOUT表现为缓冲区从满到空闲时触发*/  
	epoll_data_t data;		/* User data variable 一个联合体,看成int则可以存放一个文件描述符,看成void*可以将文件描述符信息存于结构体*/  
};
typedef union epoll_data {  
	void        *ptr;  
	int          fd;  
	uint32_t     u32;  
	uint64_t     u64;  
} epoll_data_t;
  

4.2 函数

  int epoll_create(int size)		//创建epool句柄, 预估规模, 若节点个数超过改值, epoll内部也会自动更改

int epoll_ctl(
	int epfd, 					// epoll树根节点(epoll_create返回值)
	int op, 					//EPOLL_CTL_ADD: 添加节点  EPOLL_CTL_MOD: 修改节点 EPOLL_CTL_DEL: 删除节点
	int fd, 					//文件描述符
	struct epoll_event *event)  //epoll_event结构体指针, 记录socket文件描述符的信息. 

int epoll_wait(					//返回events中存储的event个数
	int epfd, 					//epoll树的根节点
	struct epoll_event *events, //当epoll检测到改动时会将改动socket的event结构体写到该参数中.
	int maxevents, 				//events数组的最大容量
	int timeout)				//