赞
踩
OSI网络参考模型分为七层,从下往上分别为:
TCP/IP协议簇是Internet的基础,也是当今最流行的组网形式。TCP/IP是一组协议的代名词,它还包括许多协议,组成了TCP/IP协议簇。TCP/IP协议并不完全符合OSI的七层参考模型,传统的开放式系统互连参考模型,是一种通信协议的7层抽象的参考模型,其中每一层执行某一特定任务,该模型的目的是使各种硬件在相同的层次上相互通信。而TCP/IP协议簇分为四层,IP位于协议簇的第二层(对应OSI的第三层),TCP位于协议簇的第三层 (对应OSI的第四层)。TCP/IP通讯协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。这4层分别为:
通过IP地址定位到计算机网络中的一台计算机,通过端口号定位到这台计算机中的程序。
端口号规定为16位,即允许一个IP主机有2的16次方65535个不同的端口。其中:
0~1023:分配给系统的端口号
我们不可以乱用
常用协议使用的端口:HTTP:80,FTP:21,TELNET:23
1024~49151:登记端口号,主要是让第三方应用使用
但是必须在IANA(互联网数字分配机构)按照规定手续登记,
49152~65535:短暂端口号,是留给客户进程选择暂时使用,一个进程使用完就可以供其他进程使用。
在Socket使用时,可以用1024~65535的端口号
定义:即客户端/服务器结构,是软件系统体系结构
作用:充分利用两端硬件环境的优势,将任务合理分配到Client端和Server端来实现,降低了系统的通讯开销。
Socket正是使用这种结构建立连接的,一个套接字接客户端,一个套接字接服务器。
如图:
可以看出,Socket的使用可以基于TCP或者UDP协议。
定义:Transmission Control Protocol,即传输控制协议,是一种传输层通信协议
基于TCP的应用层协议有FTP、Telnet、SMTP、HTTP、POP3与DNS。
特点:面向连接、面向字节流、全双工通信、可靠
TCP建立连接
必须进行三次握手:若A要与B进行连接,则必须
此时,A告诉自己上层连接建立;B收到连接信息后告诉上层连接建立。
这样就完成TCP三次握手 = 一条TCP连接建立完成 = 可以开始发送数据
- 三次握手期间任何一次未收到对面回复都要重发。
- 最后一个确认报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态。
答:防止服务器端因为接收了早已失效的连接请求报文从而一直等待客户端请求,从而浪费资源
- “已失效的连接请求报文段”的产生在这样一种情况下:Client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。
- 这是一个早已失效的报文段。但Server收到此失效的连接请求报文段后,就误认为是Client再次发出的一个新的连接请求。
- 于是就向Client发出确认报文段,同意建立连接。
- 假设不采用“三次握手”:只要Server发出确认,新的连接就建立了。
- 由于现在Client并没有发出建立连接的请求,因此不会向Server发送数据。
- 但Server却以为新的运输连接已经建立,并一直等待Client发来数据。这样,Server的资源就白白浪费掉了。
以上答案只是表象,没有说到本质上去
那么本质是 因为tcp是全双工,为保证传输的可靠性,需要给每次传输的数据段添加序号,那么初始的序列号就是tcp三次握手真正的意义所在,而为了确保交换双方的初始序号,最少需要三次才行
采用“三次握手”的办法可以防止上述现象发生:
Client不会向Server的确认发出确认
Server由于收不到确认,就知道Client并没有要求建立连接
所以Server不会等待Client发送数据,资源就没有被浪费
TCP释放连接
TCP释放连接需要四次挥手过程,现在假设A主动释放连接:(数据传输结束后,通信的双方都可主动释放连接)
第一次挥手:A发送释放信息到B;(发出去之后,A->B发送数据这条路径就断了)
第二次挥手:B收到A的释放信息之后,回复确认释放的信息:我同意你的释放连接请求
第三次挥手:B发送“请求释放连接“信息给A
第四次挥手:A收到B发送的信息后向B发送确认释放信息:我同意你的释放连接请求
B收到确认信息后就会正式关闭连接; A等待2MSL后依然没有收到回复,则证明B端已正常关闭,于是A关闭连接
为了保证双方都能通知对方“需要释放连接”,即在释放连接后都无法接收或发送消息给对方
需要明确的是:TCP是全双工模式,这意味着是双向都可以发送、接收的
释放连接的定义是:双方都无法接收或发送消息给对方,是双向的
当主机1发出“释放连接请求”(FIN报文段)时,只是表示主机1已经没有数据要发送 / 数据已经全部发送完毕;
但是,这个时候主机1还是可以接受来自主机2的数据。
当主机2返回“确认释放连接”信息(ACK报文段)时,表示它已经知道主机1没有数据发送了
但此时主机2还是可以发送数据给主机1
当主机2也发送了FIN报文段时,即告诉主机1我也没有数据要发送了
此时,主机1和2已经无法进行通信:主机1无法发送数据给主机2,主机2也无法发送数据给主机1,此时,TCP的连接才算释放
三次握手是什么或者流程?四次握手呢?答案前面分析就是。
为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。
定义:User Datagram Protocol,即用户数据报协议,是一种传输层通信协议。
基于UDP的应用层协议有TFTP、SNMP与DNS。
特点:无连接的、不可靠的、面向报文、没有拥塞控制
应用场景:适合可以丢失一些数据但要求延迟尽量低的场景。
很多的实时应用(如IP电话、实时视频会议、某些多人同时在线游戏等)要求源主机以恒定的速率发送数据,并且允许在网络发生拥塞时候丢失一些数据,但是要求不能有太大的延时,UDP就刚好适合这种要求。
针对不同的网络通信层次,Java给我们提供的网络功能有四大类:
- 即通过
Socket
,我们才能在Andorid平台上基于TCP/IP
协议进行开发Socket
不是一种协议,而是一个编程调用接口(API
),属于传输层(主要解决数据如何在网络中传输)- Socket成对出现,是一对套接字,客户端有Socket,服务端也有Socket
一个简单的Socket通信过程会创建3个Socket对象:
public static void main(String[] args) throws IOException { //1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口 ServerSocket serverSocket = new ServerSocket(12345); InetAddress address = InetAddress.getLocalHost(); String ip = address.getHostAddress(); Socket socket = null; //2.调用accept()等待客户端连接 System.out.println("~~~服务端已就绪,等待客户端接入~,服务端ip地址: " + ip); socket = serverSocket.accept(); //3.连接后获取输入流,读取客户端信息 InputStream is=null; InputStreamReader isr=null; BufferedReader br=null; OutputStream os=null; PrintWriter pw=null; is = socket.getInputStream(); //获取输入流 isr = new InputStreamReader(is,"UTF-8"); br = new BufferedReader(isr); String info = null; while((info=br.readLine())!=null){//循环读取客户端的信息 System.out.println("客户端发送过来的信息" + info); } socket.shutdownInput();//关闭输入流 socket.close(); }
public static void main(String ... args) throws Exception{
//1.创建客户端Socket,指定服务器地址和端口
Socket socket = new Socket("127.0.0.1", 12345);
//2.获取输出流,向服务器端发送信息
OutputStream os = socket.getOutputStream();//字节输出流
PrintWriter pw = new PrintWriter(os);//将输出流包装为打印流
//获取客户端的IP地址
InetAddress address = InetAddress.getLocalHost();
String ip = address.getHostAddress();
pw.write("客户端:~" + ip + "~ 接入服务器!!");
pw.flush();
socket.shutdownOutput();//关闭输出流
socket.close();
}
UDP通信编程并没有Socket
,使用的是DatagramSocket
。
服务端:
/** * 简单的UDP通信的服务端 */ public class UdpService { public static void main(String... args) throws IOException { // 创建DatagramSocket,监听指定的端口 DatagramSocket datagramSocket = new DatagramSocket(12307); byte[] bytes = new byte[1024]; //UDP与TCP的Socket接收数据略有区别,需要创建一个DatagramPacket消息数据报对象,用于接收消息 DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length); //receive()方法进行阻塞等待读取消息 datagramSocket.receive(datagramPacket); System.out.println("接收到的数据: " + new String(datagramPacket.getData())); } }
客户端:
/** * 简单的UDP通信的服务端 */ public class UdpService { public static void main(String... args) throws IOException { // 创建DatagramSocket,监听指定的端口 // 因为UDP是无连接的,所以只要监听指定的端口的数据就可以了, // 不需要像TCP那样监听到客户端连接到指定端口后需要分配一个Socket连接 DatagramSocket datagramSocket = new DatagramSocket(12307); byte[] bytes = new byte[1024]; //UDP与TCP的Socket接收数据略有区别,需要创建一个DatagramPacket消息数据报对象,用于接收消息 DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length); //接收数据,receive()方法进行阻塞等待读取消息 datagramSocket.receive(datagramPacket); System.out.println("接收到的数据: " + new String(datagramPacket.getData())); } }
更多相关内容可参看:
Android:这是一份很详细的Socket使用攻略
10分钟理解TCP/IP各个协议以及协议之间的关系
网卡工作在数据链路层
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。