谈到网络通信就不得不提下面两点:
- OSI 7 层参考模型
- TCP/IP 协议
OSI 7 层参考模型
这只是个参考模型,具体实现的时候已将 表示层
及会话层
归纳到了 应用层
。
TCP 协议就在传输控制层。
4层(或5层)
分层其实是软件工程学中常见的实现方式,因为分层具备解耦,每个层实现自己该办的事情。层与层之间只要接口稳定,层内的东西可以替换,可以升级,可以修改,而且每一层都可以实现在不同的环境里。
如:应用层就是由开发人员去开发实现应用程序,传输控制层、网络层、链路层已由操作系统内核实现。应用层只需要调用内核提供的API即可。
为了了解 通信,我们先来来想一下:程序想发送一个 数据包 它的完整的过程是如何从你的主机出去的,怎么发送到目标服务器的。
先来看一个命令:
$ exec 8<> /dev/tcp/www.baidu.com/80
注:
exec
用于调用并执行指令的命令;8
是 文件描述符;<>
是输入输出;/dev/tcp/www.baidu.com/80
是path
这个命令执行后好像什么都没发生,但其实现在一个多了一个文件描述符 8
, 8
就代表了和百度的连接。在 8
上输入输出,就会给百度发送消息,即和百度建立了一个连接。 8
就代表了一个对百度的双向的通信(输入输出)
这时连接已经有了,那么怎么把百度的主页请求回来呢?
HTTP
要给百度发送消息,就得遵从双方的消息协议,这个协议就是: HTTP协议。
HTTP
规定的消息格式:
[方法] [URI] HTTP/[版本]
[body-消息体]
下面 echo
将会输出一个 HTTP 格式的消息:
$ echo -e "GET / HTTP/1.0 \n"
GET / HTTP/1.0
$
- 那么只要把上面打印的消息通过连接
8
,就可以把消息发送给百度 - 百度读到这个消息,就能正确解析,就知道你要请求主页,并
response
返回 - 客户端通过
response
拿到返回的结果,并将返回的结果打印,主页就显示出来了
模拟请求
将打印结果输出重定向到 8
:
$ echo -e "GET / HTTP/1.0 \n" >& 8
&
表示后面是一个文件描述符,而不是一个普通的文件名称
执行后,结果已发给 8
,不在命令行输出了。
这个时候已经把请求发出去了,那么怎么拿到 response
呢?只要读 8
即可:
$ cat <& 8
执行后,你会发现,好像什么都没有发生一样。这很正常,因为连接已经断开了。
服务器与客户端建立连接后,服务器会有一个计时,超过规定的时间,客户端没有发送消息,那么就会断开这个连接。因为每一个连接是需要消耗资源的。
你只要建立连接、发送请求、读取响应这个过程快一点就可以了。
为了演示先关掉 8
:
$ exec 8<& -
执行:
$ exec 8<> /dev/tcp/www.baidu.com/80
$ echo -e "GET / HTTP/1.0\n" >& 8
$ cat <& 8
执行结果如下图:
- 第一句语句并没有看到建立
TCP
连接的影子,因为你执行这条命令,linux 内核就帮你建立好连接了 - 第二句按照
HTTP
协议来封装报文,把数据格式化并把 数据发送给了8
- 第三句读取
8
返回的响应
这个时候你可能会说,这不就是 curl www.baidu.com
嘛,是的这就是 curl
,但是用 curl
演示的话你就 get 不到连接建立的过程了。
上面的过程有点像 nc
:
$ nc www.baidu.com 80
GET / HTTP/1.0
小结
程序员只要在 应用层,按照相应的协议封装好数据,web sever(tomcat、nginx) 做的就是上面的事情。
- 应用程序告诉内核 “我要建立一个连接”,但是内核建立好连接
- 连接建立好根据应用层协议封装好数据发送报文
- 内核从服务器拿到数据返回给应用程序