手把手写C++服务器:网络编程常见误区
Posted 沉迷单车的追风少年
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手把手写C++服务器:网络编程常见误区相关的知识,希望对你有一定的参考价值。
目录
1、业务代码和IO操作混合
业务代码和IO操作混合,对单测和维护造成极大困难,只是写时一时爽,维护火葬场。
2、TCP接受数据不完整、不可靠
TCP连接与断开的时候与条件,在设计应用层协议时候,将TCP的连接与断开放到设计中。
2、TCP是一个流
TCP是字节流协议,TCP 的模型是单个无限长度的连续流,保证字节流按顺序到达,但不保留消息边界,因为对于TCP来说本身没有消息的概念。
例如当尝试通过socket发送消息时候:
socket.write("Hi Sandy.");
socket.write("Can we appointment tonight?");
TCP 不会将写入视为单独的数据。 TCP 将所有写入视为单个连续流的一部分。因此,当发出上述写操作时,TCP 会将数据简单地复制到其缓冲区中:
TCP_Buffer = "Hi Sandy.Can we appointment tonight?"
然后尽可能快的把数据发出去。为了通过网络发送数据,TCP 和其他网络协议将会把数据分成一小块一小块的,这样就可以通过媒介传输(WiFi,以太网等等)了。为了这么做,TCP 会以它任何最合适的方式来分解数据。以下是一些有关如何分解和发送数据的示例:
- “Hi Sandy.Can we appointment tonight?”
- “Hi Sandy.Can we”,“appointment tonight?”
- “Hi San”,“tonight”,“Can we”,“tonight”,“appointment”,“dy.”
所以当发出了socket.read()
命令,然后等待接收数据。读取到的第一条数据可能是 "Hi San”。Sandy 可能正准备开始处理这个数据。在应用程序处理数据的同时,TCP 流继续接收第二个和第三个数据包。然后 Sandy 发出另一个 socket.read()
命令。并且这次她收到了 "dy.”。在使用 TCP 协议的 API 时绝没有数据包和数据分离的这些概念。
如果参考其他基于TCP设计的协议,比如HTTP 是一个很好的例子,因为它非常简单,而且因为大多数人以前都看过它。当客户端连接服务器并发送请求时,它以非常特定的方式进行。它发送一个 HTTP header,并且标头的每一行都以 CRLF(回车,换行)终止。所以像这样:
GET /page.html HTTP/1.1
Host: google.com
此外,HTTP header 的结尾由两个连续的 CRLF 作为标记。由于协议指定了终止符,因此很容易从 TCP socket 读取数据,直到到达终结符为止。
HTTP/1.1 200 OK
Content-Length: 216
{ Exactly 216 bytes of data go here }
HTTP 协议让 TCP 使用起来方便了不少。读取数据,直到获得连续的 CRLF。这就是你的 header。然后从 header 里解析出 content-length
,现在你就可以直接读取这个长度的字节数据了。
所以需要设计实现TCP分包逻辑,将TCP字节流切成一个个可以分开的消息。
当TCP写入数据时候:
- 必须将所有发送和接收的数据分解成小段,以便通过网络发送。
- TCP 处理许多复杂的问题,例如重新发送丢失的数据包,提供有序的传输,以便信息按正确的顺序到达。
因此,当发出写操作时,数据仅被复制到 OS 网络堆栈中的基础缓冲区中。这时候TCP会执行以下操作:
- 将数据分解成小块,以便可以通过网络发送
- 保证丢失的数据得到正确的重发
- 保证数据按正确的顺序送达
- 监控网络总的拥堵情况
- 采用各种各样的算法来尽快处理这些任务
4、直接发送C语言结构体
结构体存在对齐问题,如果定义全局结构体,修改全局对齐方式,会直接导致:
- 第三方library扩大,破坏二进制接口。
- 系统高度不可拓展,当增大/减少字段的时,客户端/服务端都要同时进行修改。
5、TCP自连接
什么是TCP自连接问题?
自连接就是自己连接自己的现象。当我们去连接一个正在监听的端口时,系统自动为我们分配一个临时端口去进行连接,这样就有可能分配到正在监听的端口号,然后出现自己连接自己的问题。
TCP自连接带来的危害?
当程序去connect一个不处于监听的端口时,必然期待其连接失败,如果自连接出现,就意味着该端口被占用了,那么:
- 真正需要监听该端口的服务会启动失败,抛出端口已被占用的异常。
- 客户端无法正常完成数据通信,因为这是个自连接,并不是一个正常的服务。
如何解决TCP自连接问题?
断开连接重试即可。
为什么说是坑?
因为当没意识到出现TCP自连接的时候,很难找到端口被占用的真正原因,给问题定位带来困难。具体的解决方法很简单。
参考
以上是关于手把手写C++服务器:网络编程常见误区的主要内容,如果未能解决你的问题,请参考以下文章
手把手写C++服务器:C++编译常见问题编译优化方法C++库发布方式
手把手写C++服务器:C++编译常见问题编译优化方法C++库发布方式
手把手写C++服务器(17):自测!TCP协议面试经典十连问