常见问题汇总
select/poll/epoll的用法
表头文件
#include<sys/time.h>
#include<sys/types.h>
#include<unistd.h>
定义函数
int select(int n,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout);
函数说明
select()用来等待文件描述词状态的改变。
参数n代表最大的文件描述词加1,
参数readfds、writefds 和exceptfds 称为描述词组,是用来回传该描述词的读,写或例外的状况。
底下的宏提供了处理这三种描述词组的方式:
FD_CLR(inr fd,fd_set* set);用来清除描述词组set中相关fd 的位
FD_ISSET(int fd,fd_set *set);用来测试描述词组set中相关fd 的位是否为真
FD_SET(int fd,fd_set*set);用来设置描述词组set中相关fd的位
FD_ZERO(fd_set *set); 用来清除描述词组set的全部位
参数
timeout为结构timeval,用来设置select()的等待时间,其结构定义如下
struct timeval
{
time_t tv_sec;
time_t tv_usec;
};
返回值
如果参数timeout设为NULL则表示select()没有timeout。
错误代码
执行成功则返回文件描述词状态已改变的个数,如果返回0代表在描述词状态改变前已超过timeout时间,当有错误发生时则返回-1,错误原因存于errno,此时参数readfds,writefds,exceptfds和timeout的值变成不可预测。
EBADF 文件描述词为无效的或该文件已关闭
EINTR 此调用被信号所中断
EINVAL 参数n 为负值。
ENOMEM 核心内存不足
非阻塞connect的写法
https://blog.csdn.net/lsjseu/article/details/44430253
阻塞socket和非阻塞socket的区别
阻塞IO:系统调用无法立即完成而被操作系统挂起,直到等待的事件发生为止
例如:connect函数在调用后阻塞,直到对端发生确认报文为止
可能被阻塞系统调用包括accept,send,recv
非阻塞IO:系统调用立即返回,不管事件是否发生。如果事件没有立即发生则返回-1, 设置errno
其中对于accept, send, recv来说errno如下
send/recv函数的返回值情况
#include <sys/types.h>
#include <sys/socket.h>
/*description :从sockfd写数据
*return :实际读取的长度,可能小于期望值需要多次调用recv;出错时返回-1并且设置errno
*@pram buf : 读缓冲区的位置 len:读缓冲区的大小
*/
size_t send(int sockfd, const void *buf, size_t len, int flags);
/*description :从sockfd接收数据
*return :实际读取的长度,可能小于期望值需要多次调用recv;当返回 0 时对方关闭了连接, 出错时返回-1并且设置errno
*@pram buf : 读缓冲区的位置 len:读缓冲区的大小
*/
size_t recv(int sockfd, void *buf, size_t len, int flags);
-
SO_REUSEADDR用法
-
即使sock处于TIME_WAIT状态,只要设置了SO_RCVBUF也能立即重用
也可以修改内核参数:/proc/sys/net/ipv4/tcp_rw_recycle,快速回收关闭socket,从而tcp连接不进入TIME_WAIT的状态
nagle算法
:TCP连接中有在传数据(即已经发送但是没有ACK确认),小于MSS的报文段就不能发送,直到在传数据收到ACK。并且在收到ACK确认后,TCP需要收集小数据整合到一个数据包在发送。RTT控制这发包速率
是为了减少广域网的小分组数目,从而减小网络拥塞的出现;
优点:是自适应的,确认到达的越快,数据也就发哦送的越快;而在希望减少微小分组数目的低速广域网上,则会发送更少的分组;
关闭Nagle算法
使用TCP套接字选项TCP_NODELAY可以关闭套接字选项;
keeplive选项
int keepAlive = 1; // 开启keepalive属性. 缺省值: 0(关闭)
int keepIdle = 60; // 如果在60秒内没有任何数据交互,则进行探测. 缺省值:7200(s)
int keepInterval = 5; // 探测时发探测包的时间间隔为5秒. 缺省值:75(s)
int keepCount = 2; // 探测重试的次数. 全部超时则认定连接失效..缺省值:9(次)
setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive));
setsockopt(s, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));
setsockopt(s, SOL_TCP, TCP_KEEPINTVL, (void*)&keepInterval, sizeof(keepInterval));
setsockopt(s, SOL_TCP, TCP_KEEPCNT, (void*)&keepCount, sizeof(keepCount));
使用时需要#include <netinet/tcp.h>, 否则SOL_TCP和TCP_KEEPIDLE等3个宏找不到.
https://blog.csdn.net/weixin_39540568/article/details/87889811
SO_LINGER选项
作用:用于控制clsoe系统调用在关闭TCP连接时的行为。默认情况下,close调用之后立即将TCP发送缓冲区的数据发送给对端
#include <sys/socket.h>
struct linger
{
int l_onoff /*开启(非0)关闭(0)*/
int l_linger /*滞留时间*/
};
设置不同的变量在close之后会产生三种不同的行为:
(1)l_onoff = 0,默认关闭socket
(2)l_onoff != 0,调用close立即返回,丢弃发送缓冲区的数据,发送一个RST报文,因此这是一个终止异常连接的方法
(3)l_onoff != 0, l_linger > 0;close行为取决与缓冲区是否有数据,socket是否阻塞
对于阻塞socket,close等待一段时间,直到缓冲区数据发送并且确认,如果这段时间TCP模块没有发送完数据并且得到对方确认那么close系统调用返回-1,errno = EWOWLDBLOCK
对于非阻塞,close立即返回,根据返回值和errno的值来判断数据是否发送完毕
注:
#include <netdb.h>
//查看error的字符串形式
const char *gai_strerror( int error);
对于一端出现大量close_wait或者time_wait如何解决
https://blog.csdn.net/jianghao1996/article/details/106357204
通信协议如何设计和解决数据包粘包与分片的问题
三:解决数据分包和粘包的基本策略如下
1.消息定长,比如定一个100,那么读取端每次读取数据就截取100个长度的数据,然后交给业务成去做解析
2.在消息的尾部加一些特殊字符,那么在读取数据的时候,只要读到这个特殊字符,就认为已经可以截取一个完整的数据包了,这种情况在一定的业务情况下实用。
3.读取缓存的数据是不定长的,所以我们把读取到的数据添加到我们自己的一个byte[]数组中,然后根据我们的业务逻辑来找到指定的特殊协议头部,协议长度,协议尾部,然后从我们的byte[]中获取一个完整的数据包,然后再对数据包进行业务解析就可以得到正确结果。
https://blog.csdn.net/qq513036862/article/details/53640317
心跳机制如何设计
1.应用层自己实现的心跳包
由应用程序自己发送心跳包来检测连接是否正常,服务器每隔一定时间向客户端发送一个短小的数据包,然后启动一个线程,在线程中不断检测客户端的回应, 如果在一定时间内没有收到客户端的回应,即认为客户端已经掉线;同样,如果客户端在一定时间内没有收到服务器的心跳包,则认为连接不可用。
2.使用SO_KEEPALIVE套接字选项
在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项. 不论是服务端还是客户端,一方开启KeepAlive功能后,就会自动在规定时间内向对方发送心跳包, 而另一方在收到心跳包后就会自动回复,以告诉对方我仍然在线。因为开启KeepAlive功能需要消耗额外的宽带和流量,所以TCP协议层默认并不开启默认的KeepAlive超时需要7,200,000 MilliSeconds, 即2小时,探测次数为5次。对于很多服务端应用程序来说,2小时的空闲时间太长。因此,我们需要手工开启KeepAlive功能并设置合理的KeepAlive参数
https://blog.csdn.net/weixin_41783335/article/details/95737849
断线重连机制如何设置
主要使用keeplive和心跳包的机制,检测到有断线则尝试重新连接
对IO多路复用技术的理解
https://blog.csdn.net/caspar_notes/article/details/106991119
收发数据包正确的方式,收发缓冲区如何设计
https://blog.csdn.net/e21105834/article/details/94438884
优雅的关闭
https://blog.csdn.net/e21105834/article/details/93728930
定时器如何设计
https://blog.csdn.net/haolipengzhanshen/article/details/80502994
epoll实现原理