常见网络编程问题

常见问题汇总

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实现原理

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值