本文主要是介绍深入分析网络编程中容易踩的坑,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
1.TCP没考虑粘包分包
2.UDP没考虑丢包
3.长连接没考虑应用层心跳
4.大小端字节序问题
5.多线程发送乱序问题
6.大数据没考虑分片和流量控制
7.外网没考虑加密通信
8.客户端没考虑断线重连
1.TCP没考虑粘包分包
TCP是面向连接的可靠协议,TCP是流式协议,创建TCP套接字的类型为SOCK_STREAM
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
很多同学面试时对书上的话背诵如流,在实际TCP编程中却没有处理粘包和分包的代码,以为TCP也和UDP一样,客户端每send一次,服务端就会recv一次,在本机上测试可能也没有出现问题,一旦到了线上发生粘包和分包的情况就会导致逻辑出错甚至程序崩溃。
解决方案:
1) 发送端将每个包都封装成固定的长度,比如100字节大小。如果不足100字节可通过补0或空等进行填充到指定长度;
2) 发送端在每个包的末尾使用固定的分隔符,例如\r\n。如果发生拆包需等待多个包发送过来之后再找到其中的\r\n进行合并;例如,HTTP、FTP协议;
3) 将消息分为头部和消息体,头部中保存整个消息的长度,只有读取到足够长度的消息之后才算是读到了一个完整的消息;
4) 通过自定义协议进行粘包和拆包的处理。
2.UDP没考虑丢包
在一些追求低延时的场景,为了避免TCP三次握手,我们会考虑使用UDP协议,但是却忽略了系统对丢包的容忍度,没考虑到某个关键包丢失带来的影响,没有重传重组机制。
解决方案:
结合FEC、KCP、UDT、QUIC等手段增强可靠性;
3.长连接没考虑应用层心跳
TCP连接不是指真的有一条物理的连接,而是通信双方靠状态来记录维持的,从客户端发起SYN请求开始,状态就开始有序转换了。如果不发包,我们也就无法感知对方是否掉线,虽然TCP协议本身有keepalive机制,但是默认的间隔时间特别久,也无法携带其它信息,所以发送应用层心跳是非常有必要的,能快速感知掉线以便做出通知和处理,也能及时关闭fd,释放相关资源,以节省开销。
解决方案:
使用定时器发送心跳包,多长时间或者多少次没有收到回应便断开连接;
4.大小端字节序问题
计算机硬件有两种存储数据的方式:大端字节序和小端字节序。网络通信中我们一般使用大端字节序,如果我们不按照对应的字节序来编码解码,就会得到错误的值。
5.多线程发送乱序问题
TCP虽然保证重传重组,但是我们自己要保证发送数据的有序性,特别是多线程发送时,即使加锁我们也无法保证哪个线程先发送,除非每个发送的包都是独立完整的一包,不分先后顺序,否则就可能引发乱序问题。
解决方案:
通常不建议多线程发送,而是由一个线程来负责发送。
6.大数据没考虑分片和流量控制
见过有人直接将几十M、上百M甚至几G的文件直接读到内存进行发送,试问你家内存TB级别的吗,经的起这么消耗,另外不做发送速率控制和流量控制,可能会导致网络拥塞。
解决方案:
循环从磁盘读取少量数据到内存再发送,并做好流量控制;
7.外网没考虑加密通信
在外网环境不使用SSL/TLS加密通信,就犹如一个人在大街上裸奔,没有丝毫隐私可言,安全系数为0。
解决方案:
1) 集成openssl、gnutls、mbedtls等SSL/TLS加密通信库;
2) 在网关处使用SSL代理,如使用nginx做反向代理服务;
8.客户端没考虑断线重连
网络哪没有个掉线的时候,如果没有断线重连机制,将会严重影响用户体验,试想你正在打游戏,突然掉线了,不给你自动重连,必须重新启动应用程序,是不是很影响心情。
这篇关于深入分析网络编程中容易踩的坑的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!