数据收发操作概览

知道了IP地址之后,就可以委托操作系统内部的协议栈向这个目标IP地址,也就是我们要访问的Web服务器发送消息了

和向DNS服务器查询IP地址的操作一样,这里也需要使用Socket库中的程序组件

向操作系统内部的协议栈发出委托时,需要按照指定的顺序来调用Socket库中的程序组件。

使用Socket库来收发数据的操作过程如图1.17所示。简单来说,收发数据的两台计算机之间连接了一条数据通道,数据沿着这条通道流动,最终到达目的地

我们可以把数据通道想象成一条管道,将数据从一端送入管道,数据就会到达管道的另一端然后被取出。数据可以从任何一端被送入管道,数据的流动是双向的。不过,这并不是说现实中真的有这么一条管道,只是为了帮助大家理解数据收发操作的全貌。


收发数据的整体思路就是这样,但还有一点也非常重要。光从图上来看,这条管道好像一开始就有,实际上并不是这样,在进行收发数据操作之前,双方需要先建立起这条管道才行

建立管道的关键在于管道两端的数据出入口,这些出入口称为socket。我们需要先创建socket,然后再将socket连接起来形成管道。

实际的过程是下面这样的。首先,服务器一方先创建套接字,然后等待客户端向该套接字连接管道。当服务器进入等待状态时,客户端就可以连接管道了。

具体来说,客户端也会先创建一个socket,然后从该socket延伸出管道,最后管道连接到服务器端的socket上。当双方的套接字连接起来之后,通信准备就完成了。

接下来,就像我们刚刚讲过的一样,只要将数据送入socket就可以收发数据了。

我们再来看一看收发数据操作结束时的情形。当数据全部发送完毕之后,连接的管道将会被断开。管道在连接时是由客户端发起的,但在断开时可以由客户端或服务器任意一方发起。其中一方断开后,另一方也会随之断开,当管道断开后,套接字也会被删除。到此为止,通信操作就结束了。

综上所述,收发数据的操作分为若干个阶段,可以大致总结为以下4个。

(1)创建socket(创建套接字阶段)
(2)将管道连接到服务器端的socket上(连接阶段)
(3)收发数据(通信阶段)
(4)断开管道并删除socket(断开阶段)

在每个阶段,Socket库中的程序组件都会被调用来执行相关的数据收发操作。不过,在探索其具体过程之前,我们来补充一点内容。前面这4个操作都是由操作系统中的协议栈来执行的,浏览器等应用程序并不会自己去做连接管道、放入数据这些工作,而是委托协议栈来代劳

创建socket阶段

下面我们就来探索一下应用程序(浏览器)委托收发数据的过程。这个过程的关键点就是像对DNS服务器发送查询一样,调用Socket库中的特定程序组件

首先是socket创建阶段。客户端创建套接字的操作非常简单,只要调用Socket库中的socket程序组件就可以了(图1.18①)。调用socket之后,控制流程会转移到socket内部并执行创建socket的操作,完成之后控制流程又会被移交回应用程序。

socket创建完成后,协议栈会返回一个描述符,应用程序会将收到的描述符存放在内存中

描述符是用来识别不同的套接字的,大家可以作如下理解。我们现在只关注了浏览器访问Web服务器的过程,但实际上计算机中会同时进行多个数据的通信操作,比如可以打开两个浏览器窗口,同时访问两台Web服务器。这时,有两个数据收发操作在同时进行,也就需要创建两个不同的套接字。这个例子说明,同一台计算机上可能同时存在多个套接字,在这样的情况下,我们就需要一种方法来识别出某个特定的套接字,这种方法就是描述符。我们可以将描述符理解成给某个套接字分配的编号。也许光说编号还不够形象,大家可以想象一下在酒店寄存行李时的场景,酒店服务人员会给你一个号码牌,向服务人员出示号码牌,就可以取回自己寄存的行李,描述符的原理和这个差不多。当创建套接字后,我们就可以使用这个套接字来执行收发数据的操作了。这时,只要我们出示描述符,协议栈就能够判断出我们希望用哪一个套接字来连接或者收发数据了


内部分为创建套接字、连接Web服务器、发送数据、接收数据、断开连接几个阶段。

应用程序是通过“描述符”这一类似号码牌的东西来识别套接字的。

连接阶段:把管道接上去

接下来,我们需要委托协议栈将客户端创建的socket与服务器那边的socket连接起来。应用程序通过调用Socket库中的名为connect的程序组件来完成这一操作。这里的要点是当调用connect时,需要指定描述符、服务器IP地址和端口号这3个参数(图1.18②)。

第1个参数,即描述符,就是在创建socket的时候由协议栈返回的那个描述符。connect会将应用程序指定的描述符告知协议栈,然后协议栈根据这个描述符来判断到底使用哪一个套接字去和服务器端的套接字进行连接,并执行连接的操作。

第2个参数,即服务器IP地址,就是通过DNS服务器查询得到的我们要访问的服务器的IP地址。在DNS服务器的部分已经讲过,在进行数据收发操作时,双方必须知道对方的IP地址并告知协议栈。这个参数就是那个IP地址了。

第3个参数,即端口号,这个需要稍微解释一下。可能大家会觉得,IP地址就像电话号码,只要知道了电话号码不就可以联系到对方了吗?其实,网络通信和电话还是有区别的,我们先来看一看IP地址到底能用来干什么。IP地址是为了区分网络中的各个计算机而分配的数值。因此,只要知道了IP地址,我们就可以识别出网络上的某台计算机。但是,连接操作的对象是某个具体的套接字,因此必须要识别到具体的套接字才行,而仅凭IP地址是无法做到这一点的。我们打电话的时候,也需要通过“请帮我找一下某某某”这样的方式来找到具体的某个联系人,而端口号就是这样一种方式。当同时指定IP地址和端口号时,就可以明确识别出某台具体的计算机上的某个具体的套接字

也许有人会说:“能不能用前面创建套接字时提到的那个描述符来识别套接字呢?”这种方法其实是行不通的,因为描述符是和委托创建套接字的应用程序进行交互时使用的,并不是用来告诉网络连接的另一方的,因此另一方并不知道这个描述符。同样地,客户端也无法知道服务器上的描述符。因此,客户端也无法通过服务器端的描述符去确定位于服务器上的某一个套接字。所以,我们需要另外一个对客户端也同样适用的机制,而这个机制就是端口号。如果说描述符是用来在一台计算机内部识别套接字的机制,那么端口号就是用来让通信的另一方能够识别出套接字的机制。

既然需要通过端口号来确定连接对象的套接字,那么到底应该使用几号端口呢?

服务器上所使用的端口号是根据应用的种类事先规定好的,仅此而已。比如Web是80号端口,电子邮件是25号端口。也就是说,浏览器访问Web服务器时使用80号端口,这是已经规定好的

可能大家还有一个疑问,既然确定连接对象的套接字需要使用端口号,那么服务器也得知道客户端的套接字号码才行吧,这个问题是怎么解决的呢?事情是这样的,首先,客户端在创建套接字时,协议栈会为这个套接字随便分配一个端口号。接下来,当协议栈执行连接操作时,会将这个随便分配的端口号通知给服务器。

说了这么多,总而言之,就是当调用connect时,协议栈就会执行连接操作。当连接成功后,协议栈会将对方的IP地址和端口号等信息保存在套接字中,这样我们就可以开始收发数据了。

描述符:应用程序用来识别套接字的机制
IP地址和端口号:客户端和服务器之间用来识别对方套接字的机制

通信阶段:传递消息

当socket连接起来之后,剩下的事情就简单了。只要将数据送入socket,数据就会被发送到对方的socket中。当然,应用程序无法直接控制socket,因此还是要通过Socket库委托协议栈来完成这个操作。这个操作需要使用write这个程序组件,具体过程如下。

首先,应用程序需要在内存中准备好要发送的数据。根据用户输入的网址生成的HTTP请求消息就是我们要发送的数据。接下来,当调用write时,需要指定描述符和发送数据(图1.18③),然后协议栈就会将数据发送到服务器。由于套接字中已经保存了已连接的通信对象的相关信息,所以只要通过描述符指定套接字,就可以识别出通信对象,并向其发送数据。接着,发送数据会通过网络到达我们要访问的服务器。

接下来,服务器执行接收操作,解析收到的数据内容并执行相应的操作,向客户端返回响应消息。

当消息返回后,需要执行的是接收消息的操作。接收消息的操作是通过Socket库中的read程序组件委托协议栈来完成的(图1.18③’)。调用read时需要指定用于存放接收到的响应消息的内存地址,这一内存地址称为接收缓冲区。于是,当服务器返回响应消息时,read就会负责将接收到的响应消息存放到接收缓冲区中。由于接收缓冲区是一块位于应用程序内部的内存空间,因此当消息被存放到接收缓冲区中时,就相当于已经转交给了应用程序。

断开阶段:收发数据结束

当浏览器收到数据之后,收发数据的过程就结束了。接下来,我们需要调用Socket库的close程序组件进入断开阶段(图1.18④)。最终,连接在套接字之间的管道会被断开,套接字本身也会被删除。

断开的过程如下。Web使用的HTTP协议规定,当Web服务器发送完响应消息之后,应该主动执行断开操作,因此Web服务器会首先调用close来断开连接。断开操作传达到客户端之后,客户端的socket也会进入断开阶段。

接下来,当浏览器调用read执行接收数据操作时,read会告知浏览器收发数据操作已结束,连接已经断开。浏览器得知后,也会调用close进入断开阶段。

这就是HTTP的工作过程。

HTTP协议将HTML文档和图片都作为单独的对象来处理,每获取一次数据,就要执行一次连接、发送请求消息、接收响应消息、断开的过程。因此,如果一个网页中包含很多张图片,就必须重复进行很多次连接、收发数据、断开的操作。对于同一台服务器来说,重复连接和断开显然是效率很低的,因此后来人们又设计出了能够在一次连接中收发多个请求和响应的方法。在HTTP版本1.1中就可以使用这种方法,在这种情况下,当所有数据都请求完成后,浏览器会主动触发断开连接的操作。

思考

  • 什么是协议栈?
  • 什么是套接字?

参考

如何创建一个Socket连接_maizhushu的博客-CSDN博客_建立socket连接

应用程序委托协议栈发送消息相关推荐

  1. 自动祝福程序(定时发送消息)

    有个同学找我帮忙:明天是她朋友的生日,但她没时间发送祝福,问我能不能弄个自动发送.我想,QQ并没有内置的定时发送功能,紧接着又想起了QQ刷屏助手(见我以前的博文)便用Python实现了她提出的需求. ...

  2. 小程序向webview传参_微信小程序(1)——web-view和小程序间传递参数、发送消息...

    小程序向web-view发送消息 在组件中有一个属性src(src是webview 指向网页的链接.可打开关联的公众号的文章,其它网页需登录小程序管理后台配置业务域名.) 通过设置src中GET参数即 ...

  3. 使用python+微信发送消息提醒,实现程序监控

    使用python+微信发送消息提醒,实现程序监控 使用python+微信可以非常方便的提醒自己运行的程序是否报错,监控程序运行状态 1.申请微信测试号 https://mp.weixin.qq.com ...

  4. 小程序进入客服消息中心业务(一)

    小程序进入客服消息中心业务(一) 1. 如何进入小程序客服消息中心 button按钮进入小程序客服消息中心 <button open-type="contact">点击 ...

  5. 使用C#在应用程序间发送消息

    首先建立两个C#应用程序项目. 第一个项目包含一个Windows Form(Form1),在Form1上有一个Button和一个TextBox. 第二个项目包含一个Windows Form(Form1 ...

  6. java发送qq消息_Java点餐系统和点餐小程序新加微信消息推送功能

    其实想给点餐系统加推送很久了,之前也有单门写过Java版的微信消息推送和云开发版的微信消息推送.之所以一直没有加,也是考虑到大家的学习接受度,因为做订阅消息推送是一个综合性的开发工作. 需要你既要会小 ...

  7. 微信小程序订阅消息定时发送消息

    微信小程序订阅消息定时发送消息 本人专注使用云开发,实现一个前端可以做后端以及整个项目的部署与上线. 如果觉得我讲的好就可以给我点个赞.也可以加我微信了解详情. 1.我们先要了解什么是订阅消息 而现在 ...

  8. 关于 使用python向qq好友发送消息(对爬虫的作用----当程序执行完毕或者报错无限给自己qq发送消息,直到关闭)...

    以前看到网上一些小程序,在处理完事物后会自动发送qq消息,但是一直搞不懂是说明原理.也在网上找过一些python登陆qq发送消息的文字,但是都太复杂了.今天偶然看到一篇文章,是用python调用win ...

  9. java实现微信小程序客服功能开发,后台接受用户发送消息实现关键词自动回复

    最近做了一个小程序中间用到了小程序客服功能,主要实现采集用户提问,并且针对关键词自动回复及手动回复.中间踩过很多坑,所也现在记录下来提供给大家. 准备 首先准备一个小程序,配置好域名,左边菜单栏目点击 ...

最新文章

  1. 第一周Access课总结
  2. file input 点击没反应_Java实现文件点击没反应
  3. Fiori hash and route
  4. KDT#94 为DW/BI系统建立定制工具
  5. Codeforces Round #FF (Div. 1) A. DZY Loves Sequences
  6. Prepare for Mac App Store Submission--为提交到Mac 应用商店做准备
  7. 小皮面板有php环境吗,体验phpStudy小皮面板创建LAMP/LNMP系统和建站图文
  8. java 数据结构_Java数据结构学习方法
  9. Python自带又好用的代码调试工具Pdb学习笔记
  10. 小强的HTML5移动开发之路(51)——jquerymobile中改善页面访问速度
  11. 网络传输大数据——内存映射
  12. 21-python-time,random模块的应用
  13. javaWeb毕业设计项目完整源码附带论文合集免费下载
  14. JS基础-DOM增删改-尚硅谷视频p103
  15. RemoteFX+RDP8.0+hyper-v重定向智能卡,U盾问题
  16. html将网页变成图片,保存网页为图片,教您如何将整个网页保存为图片
  17. H3C 双线路 nqa 联动
  18. 30字的完美个人简历
  19. 英雄无敌6服务器在哪个文件夹,英雄无敌6无法进入游戏解决方法_单机攻略_快吧单机游戏...
  20. 论智能的起源、进化与未来

热门文章

  1. ubuntu-桌面菜单栏、任务栏、标题栏都不见了-解决办法
  2. CSDN如何快速更换皮肤
  3. smtplib python_python模块:smtplib模块
  4. java语言编译_java在线编译-编译,java
  5. oracle 排序_Oracle数据库中SQL之过滤和排序数据
  6. lambdaQuery中EQ、NE、GT、LT、GE、LE的用法 (来自网络收集)
  7. php预编译mysql扩展_PHP-Mysqli扩展库的预编译
  8. java resultset 映射到实例_Java中,将ResultSet映射为对象和队列及其他辅助函数
  9. php spl自动加载类,php – SPL自动加载最佳实践
  10. matlab gui输入数据库,从数据库值填充Matlab GUI列表框