最近要准备面试了,总结一下Linux网络编程。
一、常用的结构体和API
结构体
1.sockaddr_in
结构体通常用于在IPv4套接字编程中表示地址信息。主要包括sin_family(地址族)、sin_addr(地址)、sin_port(端口号)。注意sin_family用__SOCKADDR_COMMON添加,会根据不同的操作系统进行适配。sin_addr里面只有一个s_addr。
struct sockaddr_in
{
__SOCKADDR_COMMON (sin_);
in_port_t sin_port; /* Port number. */
struct in_addr sin_addr; /* Internet address. */
/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr)
- __SOCKADDR_COMMON_SIZE
- sizeof (in_port_t)
- sizeof (struct in_addr)];
};
struct in_addr
{
in_addr_t s_addr;
};
2. fd_set
用来存储套接字的结构体。
常见的操作有:
FD_ZERO(fd_set *set):清空给定的文件描述符集合。
FD_SET(int fd, fd_set *set):在集合中设置指定的文件描述符。
FD_CLR(int fd, fd_set *set):从集合中清除指定的文件描述符。
FD_ISSET(int fd, fd_set *set):测试集合中指定的文件描述符是否被设置,即是否可操作。
3. pollfd
用于监听一个或者多个文件描述符的读写异常的结构体。
struct pollfd {
int fd; // 文件描述符
short events; // 监听的事件,比如POLLIN表示可读,POLLOUT表示可写
short revents; // 实际发生的事件,返回时填充
};
fd:这是要监控的文件描述符。它可以是任何支持I/O操作的文件描述符,例如socket、管道、标准输入输出等。
events:这是一个位掩码,指定了我们对这个文件描述符感兴趣的事件。常见的事件有:
POLLIN:表示关心文件描述符是否可读。
POLLOUT:表示关心文件描述符是否可写。
POLLPRI:表示关注有优先级的可读事件,通常用于带外数据。
POLLERR:表示关心错误条件。
POLLHUP:挂断事件,对端关闭连接。
POLLNVAL:无效的文件描述符。
revents:这是一个输出字段,由poll()函数填充,表示在调用期间实际发生的事件。它包含了events中请求的事件中实际发生的一个子集,也可能包含其他意外事件,如POLLERR。
4. epoll_event
用于存储与文件描述符关联的事件类型以及相关的用户数据
typedef union epoll_data
{
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event
{
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
} __EPOLL_PACKED;
网络编程函数API
1. socket
用于创建套接字。每个连接都有一个独立的套接字,类似句柄。
例如:int sockfd = socket(AF_INET, SOCK_STREAM, 0);
第一个参数是domain(域):这个参数指定了使用的协议族或地址族。常见的取值包括AF_INET(IPv4地址族)、AF_INET6(IPv6地址族)、AF_UNIX(本地通信的UNIX域套接字)等。
第二个参数是type(类型):这个参数指定了套接字的类型,常见的取值包括SOCK_STREAM(流式套接字,使用TCP)和SOCK_DGRAM(数据报套接字,使用UDP)。
第三个参数是protocol(协议):通常情况下可以指定为0,表示根据前两个参数选择默认的协议。
2. bind
把某个套接字绑定到一个初始化后的sockaddr_in上。
例如:bind(sockfd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr)
其中 sockfd 是一个文件描述符,代表需要绑定地址的套接字,addr 是一个指向存放地址信息的结构体的指针,addrlen 是地址结构体的长度。第三个参数用于更好的计算结构体的地址。
3. listen
启动套接字监听模式,以便可以接受客户端的连接请求。
例如:listen(sockfd, 10);
其中第二个参数是等待连接队列的最大长度,超过会返回拒接连接的错误
4.accept
接受客户端请求并且声称一个新的套接字描述符。注意和socket的区别,socket绑定的是本地服务器的地址,accept返回值对应的的是客户端的地址。
例如:
struct sockaddr_in clientaddr;
socklen_t len = sizeof(clientaddr);
int clientfd = accept(sockfd, (struct sockaddr*)&clientaddr, &len);
其中sockfd是一个文件描述符,由socket创建。clientaddr:这是一个指向struct sockaddr结构体的指针,用于接收连接的客户端的地址信息。len:这是一个指向socklen_t(或某些系统上的size_t)类型的指针,用于指定clientaddr指向的地址结构的大小。
5. recv
函数定义:ssize_t recv(int socket, void *buffer, size_t length, int flags);
int count = recv(clientfd, buffer, 1024, 0);
从一个已连接的客户端接收数据。buffer是缓冲区指针,1024是缓冲区大小。
6. send
函数定义:send(int socket, const void *buffer, size_t length, int flags);
int count = send(clientfd, buffer, count, 0);
向客户端发送数据
7.select
函数定义:int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
int nready = select(maxfd+1, &rset, NULL, NULL, NULL);
返回已经准备就绪的文件描述符的个数。
第一个参数是所有文件描述符里最大值+1,这是因为文件描述符是从0开始计算的。
第二个参数是指向 fd_set 结构体的指针,表示关注可读文件描述符集合。当 select() 返回时,这个集合会被修改,只保留那些当前可读的文件描述符。
第三个参数 writefds 是指向一个 fd_set 的指针,用于监控可写的文件描述符。这里传入 NULL 意味着我们不关心任何文件描述符的写就绪状态。
第四个参数 exceptfds 同样是指向一个 fd_set 的指针,用于监控异常条件(如断开连接)。传入 NULL 表示我们也不关心异常事件。
第五个参数 timeout 是一个指向 struct timeval 的指针,用于设置 select() 的超时时间。传入 NULL 表示阻塞直到至少有一个文件描述符变为可读、可写或有异常。
8. poll
select函数的改进版本,主要解决了select文件描述符限制的问题。
函数定义:int poll(struct pollfd *fds, nfds_t nfds, int timeout);
int nready = poll(fds, maxfd+1, -1);
fds: 一个指向pollfd结构体数组的指针。每个结构体定义了一个需要监控的文件描述符及其相关的事件。
nfds: 数组fds中的元素数量。这个值应该是你实际要监控的文件描述符的数量,而不是最大文件描述符值加1。
timeout: 超时时间,单位为毫秒。如果设为0,则poll立即返回;如果设为-1,则poll会一直阻塞直到有事件发生;如果是正数,则表示等待的最长时间,超时后poll也会返回。
9.epoll_create
epoll_create是Linux系统中用于创建一个 epoll 文件描述符的系统调用。
int epfd = epoll_create(1);
这里的参数传入一个正整数即可
10.epoll_ctl
epoll_ctl用于控制已经创建的epoll实例中的文件描述符集合。它允许用户添加、修改或删除对特定文件描述符的监控事件。
函数原型:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
第一个参数epfd是通过epoll_create得到的epoll文件描述符。
第二个参数EPOLL_CTL_ADD指定操作类型为添加监控。
第三个参数sockfd是要添加进epoll监控的文件描述符。可以理解为epoll实例和sockfd的绑定。
第四个参数&ev是指向epoll_event结构体的指针,包含了要监控的事件类型及关联数据。
11. epoll_wait
用于把准备就绪的事件放入某个数组中。
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
struct epoll_event events[1024] = {0};
int nready = epoll_wait(epfd, events, 1024, -1);
epfd:通过之前调用epoll_create(2)创建的epoll文件描述符。这是epoll实例的标识符。
events:一个指向epoll_event结构体数组的指针。当epoll_wait返回时,这个数组会被填充上就绪事件的信息。每个元素代表一个事件,包括触发事件的文件描述符和事件类型。
maxevents:epoll_wait调用可以返回的最大事件数量。这个参数限制了events数组的大小,防止数组溢出。
timeout:等待事件的超时时间,单位为毫秒。如果设为0,epoll_wait立即返回,无论是否有事件发生;如果设为-1,则表示无限期等待,直到至少有一个事件发生;如果是正数,则在指定的毫秒数后超时返回,即使没有事件发生。
这是一条吃饭视频,由挨踢零声赞助。