手把手写C++服务器:网络编程常见误区

Posted 沉迷单车的追风少年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手把手写C++服务器:网络编程常见误区相关的知识,希望对你有一定的参考价值。

目录

1、业务代码和IO操作混合

2、TCP接受数据不完整、不可靠

2、TCP是一个流

4、直接发送C语言结构体

5、TCP自连接

参考


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 会以它任何最合适的方式来分解数据。以下是一些有关如何分解和发送数据的示例:

  1. “Hi Sandy.Can we appointment tonight?”
  2. “Hi Sandy.Can we”,“appointment tonight?”
  3. “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语言结构体

结构体存在对齐问题,如果定义全局结构体,修改全局对齐方式,会直接导致:

  1. 第三方library扩大,破坏二进制接口。
  2. 系统高度不可拓展,当增大/减少字段的时,客户端/服务端都要同时进行修改。

5、TCP自连接

什么是TCP自连接问题?

自连接就是自己连接自己的现象。当我们去连接一个正在监听的端口时,系统自动为我们分配一个临时端口去进行连接,这样就有可能分配到正在监听的端口号,然后出现自己连接自己的问题。

TCP自连接带来的危害?

当程序去connect一个不处于监听的端口时,必然期待其连接失败,如果自连接出现,就意味着该端口被占用了,那么:

  • 真正需要监听该端口的服务会启动失败,抛出端口已被占用的异常。
  • 客户端无法正常完成数据通信,因为这是个自连接,并不是一个正常的服务。

如何解决TCP自连接问题?

断开连接重试即可。

为什么说是坑?

因为当没意识到出现TCP自连接的时候,很难找到端口被占用的真正原因,给问题定位带来困难。具体的解决方法很简单。

参考

 

以上是关于手把手写C++服务器:网络编程常见误区的主要内容,如果未能解决你的问题,请参考以下文章

手把手写C++服务器:专栏文章-汇总导航更新中

手把手写C++服务器:C++编译常见问题编译优化方法C++库发布方式

手把手写C++服务器:C++编译常见问题编译优化方法C++库发布方式

手把手写C++服务器(17):自测!TCP协议面试经典十连问

手把手写C++服务器(17):自测!TCP协议面试经典十连问

手把手写C++服务器(11):手撕网络带宽测试工具TTCP