一 前言
在之前的文章中有提过Socket(作为进程间通信的一种方式),其实Socket是封装了底层的TCP和UDP协议,为开发者提供的友好网络编程接口(注意是个编程库,不是协议),对开发者而言是网络编程的重要知识点。要了解Socket我们先从网络的基础知识讲起,看看Socket在网络模型中的位置。
二 网络基础知识
20世纪70年代Vinton Gray Cerf(文顿·瑟夫)和Robert Elliot Kahn(罗伯特·卡恩)两位先生设计了TCP/IP协议模型,奠定了现代网络的基础知识。这世上从来就没有什么理所当然就存在的事情,感谢先辈们的付出,向他们致敬。后来又经过分层设计,演变成了现在的四层模型(自上而下分为应用层、传输层、网络互联层和网络接口层)。这个四层协议模型为业界所通用,但不知道什么原因国际化标准组织搞了一个七层的OSI组织模型,这个七层模型层数太多,遭到很多专家反对,其中普度大学的教授Douglas Comer(先生在网络界的盛名不需多说)这样批评这个七层模型(下面是引用WolfcsTec翻译的教授文章原话)
研究人员开始回顾 OSI 七层参考模型的起源,琢磨这个笨重的、模糊不清的模型为什么如此的持久,总是挥之不去。他们发现了一个令人吃惊的事实。我们早就知道,这个模型是一个小组(国际化标准组织)的工作,但是我们不知道,那群人在一天夜里聚在酒吧里取笑美国的流行文化。他们在餐巾纸上胡乱写下迪斯尼电影《白雪公主和七个小矮人》中的七个小矮人的名字。有人开玩笑说,“7”对网络分层来讲是一个很好的数字。第二天上午在标准化委员会的会议上,工作组传看着餐巾纸,一致同意了他们前天夜里喝醉以后的重大发现。那天结束时,他们对七个层次重新命名(听起来更加科学),于是基本模型诞生了。以下罗列了七层的名字和一些解释:
层次 小矮人的名字 OSI分层的名字 解释
1 Sleepy Physical(物理层) . . . . . .
2 Sneezy Link (链路层) . . . . . .
3 Happy Network(网络层) . . . . . .
4 Doc Transport(传输层) . . . . . . .
5 Dopey Session(会话层) . . . . . .
6 Bashful Presentation(表示层) . . . . . .
7 Grumpy Application (应用层) . . . . . .
这个故事的教训:如果你是一个标准委员会的工程师,就不要和你的同事去喝酒——深夜里一个拙劣的笑话,有可能成为工业界几十年都挥之不去的梦魇。
好吧,教授这段话,诛心之论,那还说什么,我们就看看计算机的四层TCP/IP网络模型。
2.1 TCP/IP协议模型
废话不多说,先上一张我画的图
以应用层的Http协议简单解释这四层
- 应用层:用户在浏览器输入一个"http://"开头的url地址后,浏览器会根据网址的含义,生成HTTP请求消息。然后把消息向下转交给传输层。
- 传输层:传输层按照网络数据包的长度对数据拆分,在每个包前面加上TCP头部并向下转交给网络互联层(IP层)。
- 网络互联层:网络互联层在TCP包的前面加上IP头部,然后向下转交给接口层。
- 网络接口层:如果是以太网络时,会查询MAC地址,并加上MAC头部,向下转交给网卡驱动。
2.2 网络数据传输流程
上面说了TCP/IP协议的四层模型,好像没看到Socket(这说明他确实不是一个协议),接下来梳理网络数据传输的流程。先看自己梳理的一张网络数据在客户端/服务端之间的数据传输图。
流程很清晰,就不在多说,说几个关注点:
- 请求方,数据打包,并层层加头部向下传递;
- 接收方,数据向上层层解析;
- 在应用层生成数据后,会通过调用Socket库委托系统协议栈(TCP/IP协议)发送和接受数据;
- Scoket库封装了TCP或者UDP协议;
下面先看看TCP和UDP协议连接流程。
2.3 TCP协议
TCP是一种面向连接、面向字节流、全双工通信、可靠的协议。
2.3.1 TCP连接
先看一下TCP连接过程(也就是传说中的"三次握手"),如下图:
这里引用林沛满的一段解释(很形象):
客户端:“我能和你建立连接吗?我的初始发送序号是X。如果你答应就Ack=X+1。”
服务端:“收到,Ack=X+1。我也想和你建立连接。我的初始序号是Y,你如果答应就Ack=Y+1。”
客户端:“收到,Ack=Y+1。”
注意上面的SYN标识正在发起连接。上面三次握手完成了TCP的连接。
为什么要搞三次这么复杂,两次不行吗。两次不可靠,后面会补上为什么两次不可靠的原因。
2.3.2 TCP断开
后续加上
2.4 UDP协议
UDP协议无需连接,数据发出去就不管了。另外,UDP传输的数据包相比较TCP而言,量很少。最典型的应用场景就是DNS查询。
三 Socket
上面说了Socket是封装了TCP或者UDP协议,提供给开发者的编程接口库。
其实就实现了上面讲的TCP协议和UDP协议原理。
一般Socket使用的几个步骤:
- 创建Socket。
- 连接阶段(将管道连接到服务器)。
- 通信阶段(通信阶段)。
- 断开阶段(断开连接管理,并删除套接字)。
// 1.创建Socket对象,并指定连接服务端的IP及端口号 ,连接。
Socket socket = new Socket("192.168.0.100", 8001);
// 判断客户端和服务器是否连接成功
socket.isConnected());
// 2.通信阶段
//创建输入流对象InputStream
InputStream is = socket.getInputStream()
// 解析服务端返回数据
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
//读取解析后的数据
br.readLine();
// 从Socket 获得输出流对象OutputStream
OutputStream outputStream = socket.getOutputStream();
// 写入需要发送的数据到输出流对象中
outputStream.write("test").getBytes());
// 发送数据到服务端
outputStream.flush();
// 3.断开阶段
os.close();
// 断开 客户端发送到服务器 的连接,即关闭输出流对象OutputStream
br.close();
// 断开 服务器发送到客户端 的连接,即关闭输入流读取器对象BufferedReader
socket.close();
// 最终关闭整个Socket连接
当然也需要服务端配合。
代码地址(利用BIO模式实现):
Client端
Server 端
参考文章
[1] Wireshark网络分析就这么简单.林沛满
[2] 网络是怎样连接的.户根勤
[3] 鸟哥的Linux私房菜
重点推荐《网络是怎样连接的》这本书,本人还没看完,作者从软件到硬件,从服务器到交换机,每一方面都在行,而且文字功底好。
由于本人能力有限,有的方面理解不当,后续会根据情况继续调整。