Java Socket网络编程-总结

Java Socket网络编程


如想了解更多更全面的Java必备内容可以阅读:所有JAVA必备知识点面试题文章目录:


1、什么是网络编程?

网络编程: 主要是在发送端将信息通过规定好的协议进行组装包,在接收端按照规定好的协议把包进行解析,从而提取出对应的信息,达到通信的目的。
在网络编程中,发起连接程序,也就是发送第一次请求的程序,被称作客户端(Client),等待其他程序连接的程序被称作服务器(Server)。客户端程序可以在需要的时候启动,而服务器为了能够时刻相应连接,则需要一直启动。

2、IP地址与域名?

是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
由于IP地址不方便记忆,所以有专门创造了域名(Domain Name)的概念,来将域名和IP地址相互映射,例如163.com、sina.com等。
其实在网络中只能使用IP地址进行数据传输,所以在传输以前,需要把域名转换为IP,这个由称作DNS的服务器专门来完成。
所以在网络编程中,可以使用IP或域名来标识网络上的一台设备。

3、端口号?

为了在一台设备上可以运行多个程序,人为的设计了端口(Port)的概念,端口号只有整数,范围是从0 到65535(2^16-1),每个端口对应一个唯一的程序。
每个网络程序,无论是客户端还是服务器端,都对应一个或多个特定的端口号。由于0-1023一般被用作知名服务器的端口如FTP、HTTP、SMTP等,所以实际编程时一般采用大于 1024 以上的端口号。
使用端口号,可以找到一台设备上唯一的一个程序。所以如果需要和某台计算机建立连接的话,只需要知道IP地址或域名即可,但是如果想和该台计算机上的某个程序交换数据的话,还必须知道该程序使用的端口号。

4、DNS详细解析过程?

域名系统DNS (Domain Name System)是因特网使用的命名系统,是“域名系统”的英文缩写,是一种组织成域层次结构的计算机和网络服务命名系统,它用于TCP/IP网络,它所提供的服务是用来将主机名和域名转换为IP地址的工作。

DNS解析过程:
在这里插入图片描述

  1. 检查浏览器缓存中是否缓存过该域名对应的IP地址。
    用户通过浏览器浏览过某网站之后,浏览器就会自动缓存该网站域名对应的IP地址,
    当用户再次访问的时候,浏览器就会从缓存中查找该域名对应的IP地址,
    因为缓存不仅是有大小限制,而且还有时间限制(域名被缓存的时间通过TTL属性来设置)
    所以存在域名对应的IP找不到的情况。
    当浏览器从缓存中找到了该网站域名对应的IP地址,那么整个DNS解析过程结束,
    如果没有找到,将进行下一步骤。
    
  2. 如果浏览器缓存中没有,如果在浏览器缓存中没有找到IP,那么将继续查找本机系统是否缓存过IP。
    如果第一个步骤没有完成对域名的解析过程,
    那么浏览器会去系统缓存中查找系统是否缓存过这个域名对应的IP地址,
    也可以理解为系统自己也具备域名解析的基本能力。
    在Windows系统中,可以通过设置hosts文件来将域名手动绑定到某IP上,
    hosts文件位置在C:/Windows/System32/drivers/etc/hosts。
    对于普通用户,并不推荐自己手动绑定域名和IP,
    对于开发者来说,通过绑定域名和IP,可以轻松切换环境,可以从测试环境切换到开发环境,方便开发和测试。
    在XP系统中,黑客常常修改他的电脑的hosts文件,将用户常常访问的域名绑定到他指定的IP上,
    从而实现了本地DNS解析,导致这些域名被劫持。
    在Linux或者Mac系统中,hosts文件在/etc/hosts,修改该文件也可以实现同样的目的。
    
  3. 如果至此还没有命中域名,才会真正的请求本地域名服务器(LDNS)来解析这个域名。大约80%的域名解析到这里就完成了。
    如果在本机上无法完成域名的解析,那么系统只能请求本地域名解析服务系统进行解析,
    本地域名系统LDNS一般都是本地区的域名服务器,
    比如你连接的校园网,那么域名解析系统就在你的校园机房里,
    如果你连接的是电信、移动或者联通的网络,那么本地域名解析服务器就在本地区,由各自的运营商来提供服务。
    对于本地DNS服务器地址,Windows系统使用命令ipconfig就可以查看,
    在Linux和Mac系统下,直接使用命令cat /etc/resolv.conf来查看LDNS服务地址。
    LDNS一般都缓存了大部分的域名解析的结果,当然缓存时间也受域名失效时间控制,
    大部分的解析工作到这里就差不多已经结束了,LDNS负责了大部分的解析工作。
    
  4. 如果LDNS仍然没有命中,向根域名解析服务器(Root Server DNS)发起域名解析请求。
    LDNS域名解析器还没有完成解析的话,那么本地域名解析服务器(LDNS)将向根域名服务器(Root Server DNS)发起解析请求。
    
  5. 根域名服务器返回顶级域名服务器(gTLD Server)地址。
    根域名服务器返回的是所查域的通用顶级域(Generic top-level domain,gTLD)地址,
    常见的通用顶级域有.com、.cn、.org、.edu等。
    
  6. LDNS向顶级域名服务器(gTLD Server)发起解析请求。
    本地域名解析服务器(LDNS)向顶级域名服务器(gTLD Server)发起请求。
    
  7. gTLD服务器接收请求并返回Name Server服务器,这个Name Server就是网站注册的域名服务器。
    gTLD服务器接收本地域名服务器发起的请求,并根据需要解析的域名,找到该域名对应的Name Server域名服务器,
    通常情况下,这个Name Server服务器就是你注册的域名服务器,
    那么你注册的域名的服务商的服务器将承担起域名解析的任务。
    
  8. 向Name Server服务器发送请求,Name Server根据映射关系表找到目标IP,并返回给LDNS。
    Name Server服务器查找域名对应的IP地址,将IP地址连同TTL值返回给本地域名服务器。
    
  9. LDNS缓存这个域名和对应的IP地址。
    本地域名服务器缓存解析后的结果,缓存时间由TTL时间来控制。
    
  10. LDNS把解析的结果返回给用户,用户根据TTL值缓存到本地系统缓存中,域名解析过程至此结束。
    解析结果将直接返回给用户,用户系统将缓存该IP地址,缓存时间由TTL来控制,至此,解析过程结束。
    
5、网络的分层结构和一些基本协议?

结构及协议 详细版图一:
在这里插入图片描述
结构及协议 简化版图二:
在这里插入图片描述
结构及协议 简化版图三:
在这里插入图片描述
例:HTTP请求 对应网络模型结构及协议 简化版图四:
在这里插入图片描述

6、什么是Socket?

Socket 通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket,一个Socket由一个IP地址和一个端口号唯一确定。应用程序通常通过"套接字"向网络发出请求或者应答网络请求。 Socket是TCP/IP协议的一个十分流行的编程界面,但是,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。
Socket的基本工作过程包含以下四个步骤:

  • 创建Socket;
  • 打开连接到Socket的输入输出流;
  • 按照一定的协议对Socket进行读写操作;
  • 关闭Socket。
7、什么是TCP/IP协议?

既然是网络编程,涉及几个系统之间的交互,那么首先要考虑的是如何准确的定位到网络上的一台或几台主机,另一个是如何进行可靠高效的数据传输。这里就要使用到TCP/IP协议。
TCP/IP协议:由网络层的IP协议和传输层的TCP协议组成。 由IP地址可以唯一的确定Internet上的一台主机,IP层主要负责网络主机的定位,数据传输的路由。TCP层负责面向应用的可靠的或非可靠的数据传输机制。

8、什么是TCP协议?

8.1. TCP(Transmission Control Protocol 传输控制协议) 是一种面向连接(连接导向)的、可靠的、 基于IP的传输层协议。
TCP的工作是将消息或文件分解成更小的片段(称为数据包),在通过Internet发送。然后,这些数据包由另一个TCP层接收,然后将该数据重组为完整的文件或消息。TCP还负责对数据流进行错误检查,以确保数据的传递;如果发现错误,则TCP重新传输数据包。

8.2. 对TCP协议中首部每个字段的含义是什么?

  • 源端口号和目的端口号: 分别占用16位,用于区别主机中的不同进程。而IP地址是用来区分不同的主机的,源端口号和目的端口号配合上IP首部中的源IP地址和目的IP地址就能唯一 的确定一个TCP连接。
  • 序号: 占用32位,它表示在这个报文段中的的第一个数据字节在数据流中的序号。主要用来解决网络报文乱序的问题。
  • 确认序号: 占用32位,它包含发送确认的一端所期望收到的下一个序号,因此,确认序号应当是上次已成功收到数据字节序号加1。不过,只有当标志位中的ACK=1的时候表示应答域有效时,该确认序列号的字段才有效。主要用来解决不丢包的问题。
  • 数据偏移(首部长度): 占用4位,需要这个值是因为任选字段的长度是可变的。这个字段占4bit(最多能 表示15个32bit的的字,即4*15=60个字节的首部长度),因此TCP最多有60字节的首部。然而,没有任选字段, 正常的长度是20字节。
  • URG: 紧急指针域(后面马上就要说到)有效,用来保证TCP连接不被中断,并且督促中间层设备要尽快处理这些数据,当URG=1,表明紧急指针字段有效。。
  • ACK: 确认序号是否有效,有两个取值:0和1, 为1的时候表示应答域有效,反之0为无效。
  • PSH: 表示Push操作。PSH=1就是指在数据包到达接收端以后,立即传送给应用程序, 而不是在缓冲区中排队。
  • RST: 当RST=1时,表明TCP连接中出现严重差错,必须释放连接,然后再重新建立运输连接。
  • SYN: 表示同步序号,用来建立连接。SYN标志位和ACK标志位搭配使用,当连接请求的时候,SYN=1, ACK=0;连接被响应的时候,SYN=1,ACK=1;这个标志的数据包经常被用来进行端口扫描。扫描者发送一个只有SYN的数据包,如果对方主机响应了一个数据包回来 ,就表明这台主机存在这个端口;但是由于这种扫描方式只是进行TCP三次握手的第一次握手,因此这种扫描的成功表示被扫描的机器不很安全,一台安全的主机将会强制要求一个连接严格的进行TCP的三次握手。
  • FIN: 用来释放连接。当FIN=1时,表明此报文段的发送方的数据已发送完毕,并要求释放运输连接。
  • 窗口: 占用16位,TCP的流量控制由连接的每一端通过声明的窗口大小来提供。窗口大小为字节数,起始于确认序号字段指明的值,这个值是接收端正期望接收的字节。
  • 检验和: 接收端根据此检验和再计算判断该TCP包是否正确。
  • 紧急指针: 占用16位。紧急指针仅在URG=1时才有意义。从数据部分的首位到紧急指针所指示的位置为止为紧急数据。因此也可以说紧急指针指出了紧急数据的末尾在报文段中的位置。如何处理紧急数据属于应用的问题。一般在暂时中断通信,或中断通信的情况下使用。
  • 选项: 选项字段用于提高TCP的传输性能。因为根据数据偏移(首部长度)进行控制,该字段尽量调整其为32位的整数倍。

在这里插入图片描述

8.3. 对TCP三次握手的了解?

各个状态名称与含义:

  • CLOSED: 表示关闭状态。
  • LISTEN: 表示服务器端的某个SOCKET处于监听状态,可以接受连接了。
  • SYN_SENT:表示客户端同步已发送。
  • SYN_RECV: 表示服务器端同步已收到。
  • ESTABLISHED:表示已经建立连接。

在这里插入图片描述

TCP协议中首部主要一些值的含义【这里在上部分:TCP协议中首部每个字段的含义中已经描述过】:

  • SYN:表示同步序号,用来建立连接。
  • seq:占用32位,主要用来解决网络报文乱序的问题。
  • ACK:确认序号是否有效,1-确认序号有效,0-确认序号无效。
  • ack:占用32位,它包含发送确认的一端所期望收到的下一个序号,确认序号应当是上次已成功收到数据字节序号加1。主要用来解决不丢包的问题。

三次握手的过程:

  1. 建立连接,客户端发送SYN包到服务器,并进入SYN_SENT(同步已发送)状态,等待服务器确认。【其中报文段的头部:SYN=1(同步序号)ACK=0(确认序号无效)seq=x(客户端发送的序号)
  2. 服务器收到请求,服务器必须确认客户的数据包。同时自己也发送一个SYN包给客户端,即SYN+ACK包,此时服务器进入SYN_RECV(同步已收到)状态。【其中报文段的头部:SYN=1(同步序号)ACK=1(确认序号有效)ack=seq+1(ack确认序号=客户端发送的序号x+1)seq=y(服务器端发送的序号)
  3. 客户端收到服务器的SYN+ACK包,向服务器发送一个序列号(seq=客户端发送的序号x+1)ack=y+1(确认序号=服务器端发送的序号y+1)ACK=1(确认序号有效),此包发送完毕,客户端和服务器进入ESTAB_LISHED(已经建立连接)状态。

为什么连接建立需要三次握手,而不是两次或者四次握手?

结论:

  • 为什么不是两次握手:是为了防止失效的连接请求报文段被服务端接收,可能会导致服务器端一直等待下去,浪费服务端连接资源。
  • 为什么不是四次握手:在三次握手已经是一个可靠的通讯基础上再次握手没什么意义,浪费服务端连接资源。

为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤。
三次握手理解(A-客户端 B-服务器端):传输开始前,A知道自己的序列号,B知道自己的序列号。

  • 第一次握手,B知道了A的序列号;
  • 第二次握手,A知道了B知道它(A)的序列号;
  • 第三次握手,B知道了A知道它(B)的序列号。

这样,对于A和B而言,都知道“对方已经知道自己的序列号”这一现实,所以TCP连接可以建立。

如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认。

再如果只是两次握手,客户端仍然需要获得服务端的应答后才进入ESTABLISHED状态,而服务端在收到连接请求后就进入ESTABLISHED状态。
此时如果网络拥塞,客户端发送的连接请求迟迟到不了服务端,客户端便超时重发请求,如果服务端正确接收并确认应答,双方便开始通信,通信结束后释放连接。此时,如果那个失效的连接请求抵达了服务端,由于只有两次握手,服务端收到请求就会进入ESTABLISHED状态,等待发送数据或主动发送数据。但此时的客户端早已进入CLOSED状态,服务端将会一直等待下去,这样浪费服务端连接资源。

8.4. 对TCP四次挥手的了解?

四次挥手(Four-Way Wavehand) 即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。
由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,如下图:

各个状态名称与含义:

  • ESTABLISHED:表示已经建立连接。
  • FIN_WAIT_1:其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即 进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态。
  • FIN_WAIT_2:表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。
  • TIME_WAIT:表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED状态了。如果FIN_WAIT_1状态下,收到了对方同时带 FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态。
  • CLOSE_WAIT:表示在等待关闭。
  • LAST_ACK:被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED状态了。
  • CLOSED: 表示关闭状态。

在这里插入图片描述
TCP协议中首部主要一些值的含义【这里在上部分:TCP协议中首部每个字段的含义中已经描述过】:

  • FIN:用来释放连接。当FIN=1时,表明此报文段的发送方的数据已发送完毕,并要求释放运输连接。
  • SYN:表示同步序号,用来建立连接。
  • seq:占用32位,主要用来解决网络报文乱序的问题。
  • ACK:确认序号是否有效,1-确认序号有效,0-确认序号无效。
  • ack:占用32位,它包含发送确认的一端所期望收到的下一个序号,确认序号应当是上次已成功收到数据字节序号加1。主要用来解决不丢包的问题。

四次握手的过程:

  • 客户端发送一个FIN,用来关闭客户端到服务器端的数据传送,客户端进入FIN_WAIT_1状态。
  • 服务器端收到FIN后,发送一个ACK给客户端,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),服务器端进入CLOSE_WAIT状态。
  • 服务器端再次发送一个FIN,用来关闭服务器端到客户端的数据传送,服务器端进入LAST_ACK状态。
  • 客户端收到FIN后,客户端进入TIME_WAIT状态,接着发送一个ACK给服务器端,确认序号为收到序号+1,服务器端进入CLOSED状态。

为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?
MSL(Maximum Segment Lifetime) 译为“报文最大生存时间”,指报文在网络上存在的最长时间,超过这个时间报文将被丢弃。2MSL即两倍的MSL(2MSL一般会在1~4分钟)。【RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等】
为什么要等待2MSL后CLOSED: 因为虽然双方都同意关闭连接了,而且握手的4个报文也都发送完毕,按理可以直接回到CLOSED 状态,但是我们必须假想网络是不可靠的,你无法保证你(客户端)最后发送的ACK报文一定会被对方收到,就是说对方处于LAST_ACK 状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT 状态的作用就是用来重发可能丢失的ACK报文。

8.5. 通过TCP协议- 实现客户端与服务器端进行传输的简单小案例:

//TCP服务器端
public class TcpServer {
	public static void main(String[] args) throws Exception {
		try {
			System.out.println("Socket TCP服务器端启动....");
		 	//启动Socket服务器端
			ServerSocket serverSocket = new ServerSocket(8080);
			//等待客户端请求
			Socket accept = serverSocket.accept();
			//获取请求流
			InputStream inputStream = accept.getInputStream();
			//转换成string类型
			byte[] buf = new byte[1024];
			int len = inputStream.read(buf);
			String str = new String(buf, 0, len);
			System.out.println("服务器接受客户端内容:" + str);
		}catch (Exception e){
	  		throw e;
	    }finally {
	       serverSocket.close();         
	    }
	}
}
//TCP客户端
public class TcpClient {
	public static void main(String[] args) throws Exception {
		try {
			System.out.println("Socket TCP客户端启动....");
			Socket socket = new Socket("127.0.0.1", 8080);
			OutputStream outputStream = socket.getOutputStream();
			outputStream.write("我是客户端,我宣你".getBytes());
		}catch (Exception e){
	  		throw e;
	    }finally {
	       socket.close();        
	    }
	}
}
9、什么是UDP协议?

UDP(User Datagram Protocol 用户数据报协议): 是传输层的协议,面向无连接的;使用尽最大努力交付但不保证可靠交付;是面向报文的,数据报必须限定在64KB之内;支持一对一、一对多、多对一和多对多的交互通信;无法保证传输数据的顺序性;不提供差错纠正、队列管理、重复消除、流量控制和拥塞控制,但提供差错检测。

对UDP的首部格式的了解?

  • 源端口: 源端口号,范围(0~65535),需要对方回信时选用,不需要时全部置0.
  • 目的端口:目的端口号,范围(0~65535),在终点交付报文的时候需要用到。
  • 长度:UDP的数据报的长度(包括首部和数据)其最小值为8(只有首部)
  • 校验和:检测UDP数据报在传输中是否有错,有错则丢弃。该字段是可选的,当源主机不想计算校验和,则直接令该字段全为0。
    当传输层从IP层收到UDP数据报时,就根据首部中的目的端口,把UDP数据报通过相应的端口,上交给应用进程。
    如果接收方UDP发现收到的报文中的目的端口号不正确(不存在对应端口号的应用进程0,),就丢弃该报文,并由ICMP发送“端口不可达”差错报文给对方。
  • 伪首部:在UDP伪首部中,包含32位源IP地址,32位目的IP地址,8位填充0,8位协议,16位UDP长度。伪首部是一个虚拟的数据结构,其中的信息是从数据报所在IP分组头的分组头中提取的,既不向下传送也不向上递交,而仅仅是为计算校验和,目的是让UDP层验证数据是否已经到达正确的目的地。

在这里插入图片描述

通过UDP协议- 实现客户端与服务器端进行传输的简单小案例:

//UDP服务器端
public class UdpSocketServer {
	public static void main(String[] args) throws Exception {
		try {
			System.out.println("Socket UDP服务器端启动连接....");
			DatagramSocket ds = new DatagramSocket(8080);
			byte[] bytes = new byte[1024];
			DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
			// 阻塞,等待接受客户端发送请求
			ds.receive(dp);
			// 获取客户端请求内容
			String str=new String(dp.getData(),0,dp.getLength());
			System.out.println("str:"+str);
		}catch (Exception e){
	  		throw e;
	    }finally {
	       	ds.close();      
	    }
	}
}
//UDP客户端代码
public class UdpClient {
	 public static void main(String[] args) throws IOException {
		try {
			System.out.println("Socket UDP客户端启动连接....");
		 	DatagramSocket ds = new DatagramSocket();
		 	String str="学习Java Socket UDP网络编程";
		 	byte[] bytes= str.getBytes();
		 	DatagramPacket dp= new DatagramPacket(bytes, bytes.length,InetAddress.getByName("127.0.0.1"),8080);
		 	ds.send(dp);
		}catch (Exception e){
		  	throw e;
	    }finally {
	       	ds.close();      
	    }
	}
}

UDP应用场景:

  1. 面向数据报方式
  2. 网络数据大多为短消息
  3. 拥有大量Client
  4. 对数据安全性无特殊要求
  5. 网络负担非常重,但对响应速度要求高
  6. ……等等
10、TCP协议与UDP协议的区别?

TCP特点:

  • TCP是面向连接的协议,通过三次握手建立连接,通讯完成时要拆除连接,由于TCP是面向连接协议,所以只能用于点对点的通讯。而且建立连接也需要消耗时间和开销,效率也会稍低。
  • TCP传输数据无大小限制,以字节流方式进行大数据传输,存在粘包和拆包的问题。
  • TCP是一个可靠的协议,它能保证接收方能够完整正确地接收到发送方发送的全部数据。

UDP特点:

  • UDP是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息,由于通讯不需要连接,所以可以实现广播发送,速度快。
  • UDP传输数据时有大小限制,每个被传输的数据报必须限定在64KB之内。
  • UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。

TCP与UDP应用:

  • TCP在网络通信上有极强的生命力,例如远程连接(Telnet)和文件传输(FTP)都需要不定长度的数据被可靠地传输。但是可靠的传输是要付出代价的,对数据内容正确性的检验必然占用计算机的处理时间和网络的带宽,因此TCP传输的效率不如UDP高。
  • UDP操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的分散系统中client/server应用程序。例如视频会议系统等,并不要求数据绝对的正确,只要保证连贯性就可以了,这种情况下显然使用UDP会更合理一些。
11、TCP 短连接和长连接的区别?

长连接和短连接的产生在于 Client 和 Server 采取的关闭策略,具体的应用场景采用具体的策略。

短连接: Client 向 Server 发送消息,Server 回应 Client,然后一次读写就完成了,这时候双方任何一个都可以发起 close 操作,不过一般都是 Client 先发起 close 操作。短连接一般只会在 Client/Server 间传递一次读写操作。
优点: 管理起来比较简单,建立存在的连接都是有用的连接,不需要额外的控制手段。像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源。
缺点: 请求频繁,将在TCP的建立和关闭操作上浪费时间和带宽。

长连接: Client 与 Server 完成一次读写之后,它们之间的连接并不会主动关闭,后续的读写操作会继续使用这个连接。
优点: 可以省去较多的TCP建立和关闭的操作,减少浪费,节约时间。所以长连接适合频繁建立连接的场景。
缺点: 连接如果一直不关闭的话,会存在一个问题,随着客户端连接越来越多,server早晚有扛不住的时候,这时候server端需要采取一些策略,如关闭一些长时间没有读写事件发生的连接,这样可以避免一些恶意连接导致server端服务受损;如果条件再允许就可以以客户端机器为颗粒度,限制每个客户端的最大长连接数,这样可以完全避免某个蛋疼的客户端连累后端服务。

12、TCP粘包、拆包及解决办法?

TCP 是基于字节流的,虽然应用层和 TCP 传输层之间的数据交互是大小不等的数据块,但是 TCP 并没有把这些数据块区分边界,仅仅是一连串没有结构的字节流传输的。
什么是粘包、拆包?
第一种情况,接收端正常收到两个数据包,即没有发生拆包和粘包的现象。
在这里插入图片描述
第二种情况,接收端只收到一个数据包,但是这一个数据包中包含了发送端发送的两个数据包的信息,这种现象即为粘包。
在这里插入图片描述
第三种情况,这种情况有两种表现形式,如下图。接收端收到了两个数据包,但是这两个数据包要么是不完整的,要么就是多出来一块,这种情况即发生了拆包和粘包。
在这里插入图片描述在这里插入图片描述
为什么会发生 TCP 粘包、拆包?

  • 要发送的数据大于 TCP 发送缓冲区剩余空间大小,将会发生拆包。
  • 待发送数据大于 MSS(最大报文长度),TCP 在传输前将进行拆包。
  • 要发送的数据小于 TCP 发送缓冲区的大小,TCP 将多次写入缓冲区的数据一次发送出去,将会发生粘包。
  • 接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。

粘包、拆包解决办法?

  • 消息定长,报文大小固定长度,不够空格补全,发送和接收方遵循相同的约定,这样即使粘包了通过接收方编程实现获取定长报文也能区分。
    sc.pipeline().addLast(new FixedLengthFrameDecoder(10));
    
  • 包尾添加特殊分隔符,例如每条报文结束都添加回车换行符(例如FTP协议)或者指定特殊字符作为报文分隔符,接收方通过特殊分隔符切分报文区分。
    //比如以"|"分隔
    ByteBuf buf = Unpooled.copiedBuffer("发送的内容20200813|".getBytes());
    sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, buf));
    
  • 更复杂的应用层协议比如 Netty 中实现的一些协议都对粘包、拆包做了很好的处理。
13、TCP 流量控制?

流量控制是为了控制发送方发送速率,保证接收方来得及接收。

接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将窗口字段设置为 0,则发送方不能发送数据。

实际上,为了避免此问题的产生,发送端主机会时不时的发送一个叫做窗口探测的数据段,此数据段仅包含一个字节来获取最新的窗口大小信息。

13、TCP 拥塞控制?

如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度。
在这里插入图片描述
TCP 主要通过四个算法来进行拥塞控制:

  • 慢开始
  • 拥塞避免
  • 快重传
  • 快恢复

后续更多关于网络编程相关内容会不断更新中……


······
帮助他人,快乐自己,最后,感谢您的阅读!
所以如有纰漏或者建议,还请读者朋友们在评论区不吝指出!

个人网站…知识是一种宝贵的资源和财富,益发掘,更益分享…

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值