基于QT开发多人聊天项目6:总结

1、应用层协议的设计:

要考虑到封包格式,可能带来的问题:
1.1 以服务器给客户端回应的0X12 ID0 ID1 …为例。客户端不知道读到哪里结束,他就会一致读,可能读到的其他客户端给本客户端发来的数据。而客户端并不知道在哪里结束,所以,客户但机会误将其他客户端发来的数据当作是ID,进行显示。

1.2 粘包问题:

连续发了两次显示列表的命令,由于网络原因,可能同时发两个回来(如果不能确定每个数据包的长度)。同样不知道一个包是哪里开始,哪里就结束。
为解决上述问题,我们通过采用定义包头包尾的方式(解决数据长度未知问题)。
包头包尾的选择(避免一切在通信过程中,可能出现的符号):
这里,我们另0X02作为包头,0X03作为包尾!!
同时,还要考虑我们的ID号和我们定义的标识符冲突!!
为解决这个问题,我们用ASCII的方法来显示0-9(对应的ASCII码是30-39)
另外,我们给每个ID都分配4个字节,这样,就解决了变长的问题!
eg:ID号0012:0X30 0X30 0X31 0X32.

2、自己写的历程(实质就是测试历程)和实际应用中的历程,差距太大

自己写的历程,可能只是实现一个简单的大写转小写,然后回发的功能。这个功能简单,出问题的概率很小。而在实际的应用中,情况多变,数据复杂。
就比如:如果我使用多路IO复用的方式来创建我们的服务器,就会出现如下问题:
采用多路IO复用的方式,同样也可以共享数据链表,但是存在的问题是(这个问题,在自己写的简单历程中不会存在,在实际应用中,会存在):
当我们不能一次性的将整个包读出来的时候(eg:网络问题),如果采用阻塞的方式,会卡在read()处,直到有包尾的到达,这会直接导致对其他客户端发来请求的处理。当然,我们也可以采用非阻塞的方式读(如果一次没有读到包尾,直接跳转到epoll_wait继续监听后半部分),但是这样会存在另外一个问题。假设:在后半个包到达之前,又来了一个新的数据包。然后跳转到read(sockfd,read_buf,100);,可是这个read_buf里面已经存放的之前客户端的半个包,这个包的数据就会被覆盖。
我们可以对每个客户端都定义一个read_buf,这样,就可以解决read_buf覆盖问题。但是,又会引入一个新的问题,就是多个read_buf的管理问题。每次,当我们要使用read()函数的时候,都要找到客户端对应的那个read_buf,这就需要遍历多个read_buf。如果如果这个问题得不到优化,那么,多路IO复用的一个优点:io效率不会随着文件按描述符数目的增加而线性的下降将不复存在。

3、框架意识

在书写代码之前,要理清思路。本项目主要实现三个功能:
通过梳理这三个功能的共同点,在写完第一个功能以后,就要为接下来的两个功能搭好框架。这样,程序才会清晰明了,代码才会越写越简单。
否则,越到后面,出现的问题就越多,且很难找出原因。

4、数据据包的发送时机(tcp特性)

客户端要向服务器发送三类数据包,同样,服务器也要有三类应答的数据包。
这三个数据包的发送实际,要准确把握。
eg:
发送获取在线列表的数据包不可以 紧接着给服务器发送登录包发送的,需等待客户端解析服务器应答包函数加粗样式执行结束,再调用。
因为在不发生队报问题的时候,这种方法确实可以提高提高运行效率;但是如果发生了丢包问题,就可能会导致后面的数据包先被执行。

扩展:

TCP在不可靠的网络上实现可靠的传输,必然会有丢包。TCP是一个“流”协议,一个详细的包将会被TCP拆分为好几个包上传,也可以将小的封裝成大的上传。

TCP重传机制

TCP要保证所有的数据包都可以到达,所以,必需要有重传机制。
注意,接收端给发送端的Ack确认只会确认最后一个连续的包,比如,发送端发了1,2,3,4,5一共五份数据,接收端收到了1,2,于是回ack 3,然后收到了4(注意此时3没收到),此时的TCP会怎么办?我们要知道,因为正如前面所说的,SeqNum和Ack是以字节数为单位,所以ack的时候,不能跳着确认,只能确认最大的连续收到的包,不然,发送端就以为之前的都收到了。

超时重传机制

一种是不回ack,死等3,当发送方发现收不到3的ack超时后,会重传3。一旦接收方收到3后,会ack 回 4——意味着3和4都收到了。
但是,这种方式会有比较严重的问题,那就是因为要死等3,所以会导致4和5即便已经收到了,而发送方也完全不知道发生了什么事,因为没有收到Ack,所以,发送方可能会悲观地认为也丢了,所以有可能也会导致4和5的重传。
对此有两种选择:
一种是仅重传timeout的包。也就是第3份数据。
另一种是重传timeout后所有的数据,也就是第3,4,5这三份数据。
这两种方式有好也有不好。第一种会节省带宽,但是慢,第二种会快一点,但是会浪费带宽,也可能会有无用功。但总体来说都不好。因为都在等timeout,timeout可能会很长(在下篇会说TCP是怎么动态地计算出timeout的)

快速重传机制

于是,TCP引入了一种叫Fast Retransmit 的算法,不以时间驱动,而以数据驱动重传。也就是说,如果,包没有连续到达,就ack最后那个可能被丢了的包,如果发送方连续收到3次相同的ack,就重传。Fast Retransmit的好处是不用等timeout了再重传。
比如:如果发送方发出了1,2,3,4,5份数据,第一份先到送了,于是就ack回2,结果2因为某些原因没收到,3到达了,于是还是ack回2,后面的4和5都到了,但是还是ack回2,因为2还是没有收到,于是发送端收到了三个ack=2的确认,知道了2还没有到,于是就马上重转2。然后,接收端收到了2,此时因为3,4,5都收到了,于是ack回6。示意图如下:
在这里插入图片描述

5、基础不够扎实

这个项目用到了应用层协议设计,多线程并发服务器,线程池,链表的相关操作(创建、节点的插入(头插法)、遍历、删除…)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

One Piece&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值