在使用Socket实现进程间通信前,先对网络协议相关知识进行简单回顾。
一、网络分层
一般情况会将网络分为5层:
- 应用层 常见协议:HTTP、FTP、POP3等
- 传输层 常见协议:TCP、UDP
- 网络层 常见协议:IP
- 数据链路层
- 物理层
二、TCP与UDP区别
- TCP:面向连接的、可靠的流协议,提供可靠的通信传输。
- 所谓流,就是指不间断的数据结构,你可以把它想象成排水管道中的水流。当应用程序采用TCP发送消息时,虽然可以保证发送的顺序,但还是犹如没有任何间隔的数据流发送给接收端。
- 有顺序控制、丢包重发机制
- UDP:面向无连接的,具有不可靠性的数据报协议。(让广播和细节控制交给应用的通信传输)
- 无顺序控制、丢包重发机制
TCP用于在传输层有必要实现可靠传输的情况,由于它是面向连接并具有“顺序控制”、重发控制等机制;而UDP则主要用于那些对高速传输和实时性有较高要求的通信或广播通信。
因此TCP和UDP应该根据应用的目的按需使用,没有绝对优缺点。
三、TCP三次握手与四次挥手
使用TCP协议的连接建立与断开,正常过程下至少需要发送7个包才能完成,就是我们常说的三次握手,四次挥手。
1、标志位Flags、序号
- 序列号 Sequeuece number(seq): 数据包本身的序列号,初始序列号是随机的。
- 确认号 Acknowledgment number(ack): 在接收端,用来通知发送端数据成功接收
- 标志位,标志位只有为 1 的时候才有效
- SYN(synchronize):表示在连接建立时用来同步序号。
- ACK:TCP协议规定,只有ACK=1时有效,也规定连接建立后所有发送的报文的ACK必须为1.
- FIN(finish):用来释放一个连接。当FIN=1时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。
2、三次握手
三次握手:是指建立一个TCP连接时需要客户端和服务端总共发送3个包确认连接的建立。在Socket编程中,这一个过程由客户端执行connect来触发。
- 第一次握手:客户端向服务端发送请求报文;即SYN=1,ACK=0,seq=x。
- 第二次握手:服务端收到客户端的请求报文,服务端会确认应答,告诉客户端已经收到请求了;即SYN=1,ACK=1,seq=y,ack=x+1;
- 第三次握手:客户端收到服务端的确认应答后,再次向服务端进行确认应答,建立完整的连接;即ACK=1,seq=x+1,ack=y+1
为什么要进行三次握手呢,或两次确认??
下面使用Wireshark抓包工具体验下三次握手的过程
红色框内就是一个TCP建立连接的过程
- 53324 —>80:嘿,哥们,我想访问你的web资源,能不能把你的80端口打开
- 80 —> 53324:可以啊,我已经把80端口打开了,为了保证我们的数据能可靠传输,你那边也需要把53324端口打开;
- 53324 —> 80:没问题,我已经把53324端口打开了,尽管的发送数据过来吧。
下面看看在三次握手的标志位的变化
1、53324 —>80
2、80 —> 53324
3、53324 —> 80
3、四次挥手
四次挥手:即终止TCP连接,就是断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在Socket编程中,这一工程由客户端或服务端任意一方执行close来触发。
由于 TCP 连接是全双工的,因此每个方向都必须单独进行关闭。这一原则是当一方数据发送完成,发送一个标志位为 FIN
的报文来终止这一方向的连接,收到标志位为 FIN 的报文意味着这一方向上不会再收到数据了。但是在 TCP
连接上仍然能够发送数据,直到这一方向也发送了 FIN 。发送 FIN 的一方执行主动关闭,另一方则执行被动关闭。
- 第一次挥手:客户端发送一个FIN=1,用来关闭客户端到服务器端的数据传送,客户端进入FIN_WAIT_1状态。意思是说”我客户端没有数据要发给你了”,但是如果你服务器端还有数据没有发送完成,则不必急着关闭连接,可以继续发送数据。
- 第二次挥手:服务器端收到FIN后,先发送ack=u+1,告诉客户端,你的请求我收到了,但是我还没准备好,请继续你等我的消息。这个时候客户端就进入FIN_WAIT_2
状态,继续等待服务器端的FIN报文。- 第三次挥手:当服务器端确定数据已发送完成,则向客户端发送FIN=1报文,告诉客户端,好了,我这边数据发完了,准备好关闭连接了。服务器端进入LAST_ACK状态。
- 第四次挥手:客户端收到FIN=1报文后,就知道可以关闭连接了,但是他还是不相信网络,怕服务器端不知道要关闭,所以发送ack=w+1后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。服务器端收到ACK后,就知道可以断开连接了。客户端等待了2MSL后依然没有收到回复,则证明服务器端已正常关闭,那好,我客户端也可以关闭连接了。最终完成了四次握手。
四、Socket介绍
1、Socket定义
- 即套接字,是应用层 与 TCP/IP 协议族通信的中间软件抽象层,表现为一个封装了 TCP / IP协议族 的编程接口(API)
- Socket不是一种协议,而是一个编程调用接口(API),属于传输层(主要解决数据如何在网络中传输)
- 即:通过Socket,我们才能在Andorid平台上通过 TCP/IP协议进行开发
- 对用户来说,只需调用Socket去组织数据,以符合指定的协议,即可通信
- 位于传输层,是网络上的两个程序通过一个双向的通信连接 实现数据的交换的一种进程通信方式之一。
- 成对出现,一对套接字
Socket socket = new Socket("localhost", 8888);
localhost:IP地址
8888:端口号
即: IP地址 -- 端口号成对出现
socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供了网络开发所用的接口;HTTP是轿车,提供了封装或显示数据的具体形式;socket是发动机,提供了网络通信的能力。
典型的应用就是C/S结构:
从图可知,socket的使用是基于TCP或UDP协议。
2、Socket建立连接过程
3、原理
Socket的使用类型主要有两种:
- 流套接字(streamsocket) :基于 TCP协议,采用 流的方式 提供可靠的字节流服务
- 数据报套接字(datagramsocket):基于 UDP协议,采用 数据报文 提供数据打包发送的服务
具体原理图如下:
4、Socket 与 Http 对比
- Socket属于传输层,因为 TCP / IP协议属于传输层,解决的是数据如何在网络中传输的问题
- HTTP协议 属于 应用层,解决的是如何包装数据
由于二者不属于同一层面,所以本来是没有可比性的。但随着发展,默认的Http里封装了下面几层的使用,所以才会出现Socket & HTTP协议的对比:(主要是工作方式的不同):
- Http:采用 请求—响应 方式。
- 即建立网络连接后,当 客户端 向 服务器 发送请求后,服务器端才能向客户端返回数据。
- 可理解为:是客户端有需要才进行通信
- Socket:采用 服务器主动发送数据 的方式
- 即建立网络连接后,服务器可主动发送消息给客户端,而不需要由客户端向服务器发送请求
- 可理解为:是服务器端有需要才进行通信
5、Socket java简单实现
我们知道socket是基于TCP或UDP协议实现的,下面以TCP协议为例实现,因为TCP更加常用些。
1.1 使用步骤
- 客户端
- 创建socket对象,指定成对的服务端IP地址和端口号
- 通过socket获取输出流,写入数据发给服务端
- 通过socket获取输入流,接受服务端的发送的数据
- 关闭资源close
- 服务端(与服务端类似)
- 创建ServerSocket对象,并指定端口号,其端口号必须与客服端一致
- 通过ServerSocket对象,获取客户端的socket实例(ServerSocket.accept方法)
- 通过socket获取输入流,接受客户端发来的消息
- 通过socket获取输出流,写入数据向客户端发送数据作为回应
- 关闭资源close
1.2 具体实例
客户端Client
public class Client {
private static final String TAG = "Client";
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
//IO操作不能放在主线程执行
connectServer();
}
}).start();
}
private static void connectServer() {
try {
//1、创建客户端socket,指定服务端地址和端口
Socket socket = new Socket("localhost", 8888);
boolean connected = socket.isConnected()