Java网络编程详解(非常全面)

Java网络编程详解(非常全面)-mikechen

Java网络编程对于Java工程师来说是很重要的能力,尤其是大厂对网络编程有较高的要求 @mikechen

比如在直播、实时通讯、游戏服务端开发等技术领域,通信协议和网络编程就成为了很重要的一个技术课题。

再比如你想做基础技术研发,比如消息队列、RPC框架的研发,那么网络编程也是必备的基础能力。

计算机网络

在学习Java网络编程之前,我们先来了解什么是计算机网络。

计算机网络是通过传输介质、通信设施和网络通信协议,把分散在不同地点的计算机设备互连起来的,实现资源共享和数据传输的系统。

网络编程就是编写程序使互联网的两个(或多个)设备(如计算机)之间进行数据传输。

Java网络编程详解(非常全面)-mikechen

计算机网络主要包括三部分:

  • 计算机 (可以包括客户端、服务器)
  • 网络设备 (路由器、交换机、防火墙等)
  • 传输介质(可以分为有线和无线的)

 

按照地域范围可以对网络进行如下分类:

  • 局域网 :小范围内的私有网络,一个家庭内的网络、一个公司内的网络、一个校园内的网络都属于局域网。
  • 广域网:把不同地域的局域网互相连接起来的网络。运营商搭建连接远距离区域的广域网。
  • 互联网:由世界各地的局域网和广域网连接起来的网络,互联网是一个开放、互联的网络,不属于任何个人和任何机构。

Java网络编程详解(非常全面)-mikechen

 

网络体系结构

计算机网络是个复杂的系统,按照人们解决复杂问题的方法,把计算机网络实现的功能分到不同的层次上,层与层之间用接口连接。

七层模型

网络模型不是一开始就有的,在网络刚发展时,网络协议是由各互联网公司自己定义的,各家的协议也是不能互通的。这样大大的阻碍了互联网的发展,为了解决这个问题,国际标准化组织 1984 提出的模型标准,简称 OSI(Open Systems Interconnection Model),具体如下图:

Java网络编程详解(非常全面)-mikechen

简述每一层的含义:

1.物理层(Physical Layer)

建立、维护、断开物理连接。

2.数据链路层 (Link)

逻辑连接、进行硬件地址寻址、差错校验等。

3.网络层 (Network)

进行逻辑寻址,实现不同网络之间的路径选择。

4.传输层 (Transport)

定义传输数据的协议端口号,及流控和差错校验。

5.会话层(Session Layer)

建立、管理、终止会话。

6.表示层(Presentation Layer)

数据的表示、安全、压缩。

7.应用层 (Application)

网络服务与最终用户的一个接口

这一模型确实是绝大多数网络编程的基础,作为抽象类存在的,而TCP/IP协议栈只是这一模型的一个具体实现。

 

TCP/IP模型

TCP/IP 模型是由 OSI 模型演化而来,TCP/IP 模型将 OSI 模型由七层简化为五层(一开始为四层),应用层、表示层、会话层统一为应用层。

Java网络编程详解(非常全面)-mikechen

 

网络协议

如同人与人之间相互交流是需要遵循一定的规矩一样,计算机之间能够进行相互通信是因为它们都共同遵守一定的规则,即网络协议。

 

TCP协议

TCP 是面向连接的,提供端到端可靠性服务的传输层协议。

TCP协议特点

1)面向连接型的传输协议

也就是说,应用程序在使用TCP之前,必须先建立TCP传输连接,在传输数据完毕后,必须释放已建立的TCP传输连接。

2)仅支持单播传输

每条TCP传输连接只能有两个端点,只能进行点对点的数据传输,不支持多播(multicast)和广播(broadcast)传输方式。

3)支持全双工传输

TCP允许通信双方的应用程序在任何时候都能发送数据,因为TCP连接的两端都设有缓存,用来临时存放双向通信的数据。当然,TCP可以立即发送一个数据段,也可以缓存一段时间以便一次发送更多的数据段(最大的数据段大小取决于MSS)。

4)TCP连接是基于字节流的,而非报文

TCP不像UDP一样那样一个个报文独立地传输,而是在不保留报文边界的情况下以字节流方式进行传输。

5)每次发送的TCP数据段大小和数据段数都是可变的

在TCP中,因为每次发送多少字节的数据不是固定的,也不是由主机当前可用缓存决定的,而是根据双方给出的窗口大小和当前网络的拥塞程度决定的(后面会介绍UDP发送的报文长度是由应用进程给出的),所以每次可以发送的TCP数据大小是不固定的。

 

TCP的报文格式

Java网络编程详解(非常全面)-mikechen

1)源端口

数据发送方的端口号。

2)目的端口

数据接受方的端口号。

3)序号

seq序号,占4个字节,用来标识从TCP发送端向TCP接收端发送的数据字节流。

4)确认号

ack序号,即接收端希望收到的下一个数据报文中的第一个字节的序号。

5)数据偏移

占4个字节,用于指出TCP首部长度,若不存在选项,则这个值为20字节,数据偏移的最大值为60字节。
保留字段占6位,暂时可忽略,值全为0。

6)6个标志位

  • URG(紧急):为1时表明紧急指针字段有效
  • ACK(确认):为1时表明确认号字段有效
  • PSH(推送):为1时接收方应尽快将这个报文段交给应用层
  • RST(复位):为1时表明TCP连接出现故障必须重建连接
  • SYN(同步):在连接建立时用来同步序号
  • FIN(终止):为1时表明发送端数据发送完毕要求释放连接

7)接收窗口

占2个字节,用于流量控制和拥塞控制,表示当前接收缓冲区的大小。在计算机网络中,通常是用接收方的接收能力的大小来控制发送方的数据发送量。TCP连接的一端根据缓冲区大小确定自己的接收窗口值,告诉对方,使对方可以确定发送数据的字节数。

8)校验和

占2个字节,范围包括首部和数据两部分。

9)选项

长度可变,最长可达40个字节,当没有使用“选项”时,TCP的首部长度是20字节。

报文格式例子

Java网络编程详解(非常全面)-mikechen

 

三次握手

Java网络编程详解(非常全面)-mikechen

1. 第一次握手(客户端发送请求)

客户机发送连接请求报文段到服务器,并进入SYN_SENT状态,等待服务器确认。

发送连接请求报文段内容:SYN=1,seq=x;SYN=1意思是一个TCP的SYN标志位置为1的包,指明客户端打算连接的服务器的端口;seq=x表示客户端初始序号x,保存在包头的序列号(Sequence Number)字段里。

2. 第二次握手(服务端回传确认)

服务器收到客户端连接请求报文,如果同意建立连接,向客户机发回确认报文段(ACK)应答,并为该TCP连接分配TCP缓存和变量。

服务器发回确认报文段内容:SYN=1,ACK=1,seq=y,ack=x+1;SYN标志位和ACK标志位均为1,同时将确认序号(Acknowledgement Number)设置为客户的ISN加1,即x+1;seq=y为服务端初始序号y。

3. 第三次握手(客户端回传确认)

客户机收到服务器的确认报文段后,向服务器给出确认报文段(ACK),并且也要给该连接分配缓存和变量。

此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。客户端发回确认报文段内容:ACK=1,seq=x+1,ack=y+1;ACK=1为确认报文段;seq=x+1为客户端序号加1;ack=y+1,为服务器发来的ACK的初始序号字段+1。

 

四次挥手

Java网络编程详解(非常全面)-mikechen

1. TCP客户端发送一个FIN,用来关闭客户端到服务端的数据传送,客户端进入FIN_WAIT_1状态。发送报文段内容:FIN=1,seq=u;FIN=1表示请求切断连接;seq=u为客户端请求初始序号。

2. 服务端收到这个FIN,它发回一个ACK给客户端,确认序号为收到的序号加1,和SYN一样,一个FIN将占用一个序号。服务端进入CLOSE_WAIT状态。发送报文段内容:ACK=1,seq=v,ack=u+1;ACK=1为确认报文;seq=v为服务器确认初始序号;ack=u+1为客户端初始序号加1。

3. 服务器关闭客户端的连接后,发送一个FIN给客户端,服务端进入LAST_ACK状态。发送报文段内容:FIN=1,ACK=1,seq=w,ack=u+1;FIN=1为请求切断连接,ACK=1为确认报文,seq=w为服务端请求切断初始序号。

4. 客户端收到FIN后,客户端进入TIME_WAIT状态,接着发回一个ACK报文给服务端确认,并将确认序号设置为收到序号加1,服务端进入CLOSED状态,完成四次挥手。发送报文内容:ACK=1,seq=u+1,ack=w+1;ACK=1为确认报文,seq=u+1为客户端初始序号加1,ack=w+1为服务器初始序号加1。

为什么是三次握手四次挥手

因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭socket,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文,我收到了”。只有等到服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送,故需要四步挥手。

 

TCP/IP协议

TCP/IP协议被称为传输控制协议/互联网协议,又称网络通讯协议(Transmission Control Protocol),是由网络层的IP协议和传输层的TCP协议组成,是一个很大的协议集合。

  1. 物理层和数据链路层没有定义任何特定协议,支持所有的标准和专用的协议;
  2. 网络层定义了网络互联也就是IP协议,主要包括IP、ARP、RARP、ICMP、IGMP;
  3. 传输层定义了TCP和UDP(User Datagram Protocol),我们会后面重点介绍一下TCP协议;
  4. 应用层定义了HTTP(超文本传输协议)、FTP(文件传输协议)、DNS(域名系统)等协议。

 

UDP协议

UDP,用户数据报协议,英文全称是User Datagram Protocol,它是TCP/IP协议簇中无连接的运输层协议。

UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。

简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。

 

UDP协议格式

UDP 报文格式相对于简单,如下图:

Java网络编程详解(非常全面)-mikechen

1)源端口

发送方端口号,端口号0-65535,1-1024保留端口号,为标准的服务端口。

2)目的端口

接收方端口号

3)报文长度

UDP 用户数据报的总长度,以字节为单位。

4)校验和

检测 UDP 用户数据报在传输中是否有错,有错就丢弃。

用于校验 UDP 数据报的数字段和包含 UDP 数据报首部的“伪首部”。

5)数据

UDP 的数据部分如果不为偶数需要用 0 填补,就是说,如果数据长度为奇数,数据长度加“1”。

 

UPD与TCP的区别

  1. TCP基于连接,UDP是无连接的;
  2. 对系统资源的要求,TCP较多,UDP较少;
  3. UDP程序结构较简单;
  4. TCP是流模式,而UDP是数据报模式;
  5. TCP保证数据正确性,而UDP可能丢包;TCP保证数据顺序,而UDP不保证;

 

HTTP协议

HTTP,超文本传输协议,英文全称是Hypertext Transfer Protocol,它是互联网上应用最为广泛的一种网络协议。

HTTP是一种应用层协议,它是基于TCP协议之上的请求/响应式的协议,即一个客户端与服务器建立连接后,向服务器发送一个请求。

服务器接到请求后,给予相应的响应信息,HTTP协议默认的端口号为80。

http请求报文格式

HTTP请求报文主要由请求行、请求头部、请求正文3部分组成:

Java网络编程详解(非常全面)-mikechen

http返回报文格式

HTTP响应报文主要由状态行、响应头部、响应正文3部分组成

Java网络编程详解(非常全面)-mikechen

HTTP和HTTPS的区别

HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单来说就是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。它是一个URL scheme(抽象标识符体系),句法类同http:体系,用于安全的HTTP数据传输。https:URL表明它使用了HTTP,但HTTPS存在不同于HTTP的默认端口及一个加密/身份验证层(在HTTP与TCP之间)。

HTTPS和HTTP的区别主要为以下四点:

  1. https协议需要到ca申请证书,一般免费证书很少,需要缴费。
  2. http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
  3. http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
  4. http的连接很简单,是无状态的,https协议是有ssl+http协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

 

 

Java网络编程

在Java中,提供了两个类用于实现TCP通信程序:

1.客户端

java.net.Socket 类表示。创建Socket对象,向服务端发出连接请求,服务端响应请求,两者建立连接开始通信。

2.服务端

java.net.ServerSocket 类表示。创建ServerSocket对象,相当于开启一个服务,并等待客户端的连接。

Java的网络编程主要涉及到的内容是Socket编程,那么什么是Socket呢?简单地说,Socket,套接字,就是两台主机之间逻辑连接的端点。

TPC/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。Socket,本质上就是一组接口,是对TCP/IP协议的封装和应用(程序员层面上)。

 

Socket

java.net.Socket 类代表客户端和服务器都用来互相沟通的套接字,套接字指的是两台设备之间通讯的端点。

Socket 类有 5 个构造方法:

Java网络编程详解(非常全面)-mikechen

Socket 常用方法

下面列出了一些感兴趣的方法,注意客户端和服务器端都有一个 Socket 对象,所以无论客户端还是服务端都能够调用这些方法。

Java网络编程详解(非常全面)-mikechen

ServerSocket

ServerSocket类:这个类实现了服务器套接字,该对象等待通过网络的请求。

ServerSocket 有多个构造方法:

Java网络编程详解(非常全面)-mikechen

ServerSocket 类的常用方法:

Java网络编程详解(非常全面)-mikechen

Socket 通信示例

服务端示例:

public class HelloServer {

    public static void main(String[] args) throws Exception {
        // Socket 服务端
        // 服务器在8888端口上监听
        ServerSocket server = new ServerSocket(8888);
        System.out.println("服务器运行中,等待客户端连接。");
        // 得到连接,程序进入到阻塞状态
        Socket client = server.accept();
        // 打印流输出最方便
        PrintStream out = new PrintStream(client.getOutputStream());
        // 向客户端输出信息
        out.println("hello world");
        client.close();
        server.close();
        System.out.println("服务器已向客户端发送消息,退出。");
    }

}

客户端例子:

public class HelloClient {

    public static void main(String[] args) throws Exception {
        // Socket 客户端
        Socket client = new Socket("localhost", 8888);
        InputStreamReader inputStreamReader = new InputStreamReader(client.getInputStream());
        // 一次性接收完成
        BufferedReader buf = new BufferedReader(inputStreamReader);
        String str = buf.readLine();
        buf.close();
        client.close();
        System.out.println("客户端接收到服务器消息:" + str + ",退出");
    }

}

 

陈睿mikechen

10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。

关注「mikechen」公众号,获取更多技术干货!

后台回复面试即可获取《史上最全阿里Java面试题总结》,后台回复架构,即可获取《阿里架构师进阶专题全部合集

评论交流
    说说你的看法