Java 网络编程总结(精华版)

WilliamGates
发布于 2023-9-28 10:44
浏览
0收藏

一、简介

说起网络,相信大家都不陌生,把分散在不同地点的计算机设备,通过传输介质、通信设施和网络通信协议,实现资源共享和信息传输的系统,我们称之为:计算机网络系统

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

为了使两个设备之间能进行数据传输,必须在它们之间建立通信工具(即接口),使彼此之间能进行信息交换,工具包括两部分:

  • 硬件部分:实现节点之间的信息互传,比如光猫、网线
  • 软件部分:规定双方能进行通信的约定协议,比如 TCP/IP

从软件角度看,计算机网络可以分为网络体系结构和网络协议两部分。

二、网络体系结构

通过网络将数据从一台主机发送到另外的主机上,其实是一项非常复杂的操作,必须仔细地协调网络上的物理特性以及所发送数据的逻辑特征。

计算机网络体系结构,其实是计算机网络层次和协议的集合。网络体系结构对计算机网络实现的功能,以及网络协议、层次、接口和服务之间的通信进行了约定描述,但并不涉及具体的实现。

在网络体系结构中,网络设备之间的通信被分解为多个层,每一层只与紧挨其上和其下的层对话,层与层之间用接口连接(接口指的是同一节点内相邻层之间交换信息的连接处,也叫服务访问点)。

通信的双方必须具有相同的层次,层次实现的功能由协议数据单元(PDU)来描述,不同系统中的同一层构成对等层,对等层之间通过对等层协议进行通信,理解彼此定义好的规则和约定。

将网络进行分层,这样即使要修改甚至替换某一层的软件,只要层与层之间的接口保持不变,就不会影响到其他层。

Java 网络编程总结(精华版)-鸿蒙开发者社区

世界上第一个网络体系结构由 IBM 公司提出,之后其他公司也相继提出自己的网络体系结构。为了促进计算机网络的发展,国际标准化组织 ISO 在现有网络的基础上,提出了不基于具体机型、操作系统或公司的网络体系结构,称为开放系统互连参考模型,即 OSI/RM(Open System Interconnection Reference Model)。

OSI 模型把网络通信的工作分为 7 层,分别是应用层、表示层、会话层、传输层、网络层、数据链路层和物理层。

由于 OSI 模型过于庞大、复杂招致了许多批评,与此相对,美国国防部提出了 TCP/IP 参考模型,把网络通信的工作分为 4 层,分别是应用层、传输层、网络层、网络接口层,简化了 OSI 参考模型。

由于 TCP/IP 参考模型的简单,获得了广泛的应用,并成为后续网络通信事实上的标准。

Java 网络编程总结(精华版)-鸿蒙开发者社区

这里我们要重点说一下 TCP/IP 参考模型。

TCP/IP,即 Transmission Control Protocol/Internet Protocol 的简写,中译名为传输控制协议/因特网互联协议,是 Internet 最基本的协议,也是国际互联网络的基础。

它的名字主要取自最重要的网络层 IP 协议和传输层 TCP 协议。TCP/IP 协议定义了电子设备如何连入因特网,以及数据如何在它们之间传输。

TCP/IP 参考模型采用 4 层的层级结构,每一层都呼叫它的下一层所提供的协议来完成自己的需求,TCP/IP 参考模型与 OSI 参考模型的关系如下:

Java 网络编程总结(精华版)-鸿蒙开发者社区

各个层级职责描述如下:

  • 应用层:为 Internet 中的各种网络应用提供服务,比如 http、ftp 等服务。
  • 传输层:也被称为 TCP 层,负责在应用进程之间建立端到端的连接和可靠通信,它只存在与端节点中,传输层涉及两个协议,TCP 和 UDP。
  • 网络层:也称为 IP 层,它是整个 TCP/IP 协议栈的核心,它的功能是把数据路由到目标网络或主机上。
  • 网络接口层:TCP/IP 协议对网络接口层没有给出具体的描述,对应着 OSI 参考模型,网络接口层指的的是物理层和数据链路层的集合。

三、网络协议

了解完网络体系结构后,相信我们对网络设备之间的数据传输已经有了初步的认识。计算机之间能够进行相互通信,主要是因为它们都共同遵守一定的规则,就如同人与人之间能相互交流是因为大家使用了共同的语言文字一样,这些规则我们称之为网络协议。

OSI 参考模型和 TCP/IP 参考模型在不同的层次下的网络协议,如下图:

Java 网络编程总结(精华版)-鸿蒙开发者社区

网络协议之间的关系图如下:

Java 网络编程总结(精华版)-鸿蒙开发者社区

下面我们一起来了解一下几个比较重要的网络协议。

3.1、IP 协议

IP 协议的作用在于把各种数据包准备无误的传递给其他设备,其中 IP 地址和 MAC 地址都可以代表设备在网络中的唯一标识。

先说说 IP 地址。

IP 地址又被称为逻辑地址,当设备连接上网络时,由路由器给设备生成一个在当前网络下唯一的 IP 地址。

同时 IP 地址又分为 IPv4 和 IPv6。

  • IPv4:指的是给每个连接在网络上的主机设备分配一个 32bit 长度的地址,用二进制来表示,由于 1 个字节等于 8 个 bit,因此 IP 地址可以用 4 个字节数表示。例如一个采用二进制形式的 IP 地址​​11000000 10101000 00000001 01000010​​​,这么长的地址处理起来太费劲了,为了方便使用,IP 地址被写成十进制的形式,中间使用符号​​.​​​分隔不同的字节,因此上面的 IP 地址可以用十进制​​192.168.1.66​​​表示,IP 地址的这种表示法叫做​​点分十进制法​​,这显然比 1 和 0 更容易记住。
  • IPv6:由于互联网的蓬勃发展,IP 地址的需求量愈来愈大,但是网络地址资源有限的,使得 IP 的分配越发紧张。为了扩大地址空间,通过 IPv6 重新定义地址空间,采用 128bit 地址长度,每 16 个字节一组,分成 8 组十六进制数,这就解决了网络地址资源数量不够的问题,例如​​abcd : 1234 : aCA9 : 123 : 4567 : 089 : 0 : 0000​​。

以​​windows​​​系统为例,可以在 DOS 中输入​​ipconfig​​命令获取本机的 IP 地址。

关于 IP 地址的划分,也有讲究!

  • ​127.0.0.1​​:表示回送地址,也代表本机地址,一般用来测试使用
  • ​190.168.0.0 – 192.168.255.255​​:表示私有地址,属于非注册地址,专门为组织内部使用,也被称为内网地址

再来说说设备的 MAC 地址。

MAC 地址也叫物理地址、硬件地址,由网络设备制造商生产时烧录在网卡的 EPROM 上。MAC 地址的长度为 48 位(6 个字节),通常用 12 个十六进制数来表示,每 2 个十六进制数之间用冒号隔开,如​​08:00:20:0A:8C:6D​​就是一个 MAC 地址,只要不更改自己的 MAC 地址,MAC 地址在全球是唯一的,但是可以肉眼得出结论,它比 IPv4 地址更难记忆。

既然 Mac 地址也具有唯一性,为何不能作为 ip 地址资源呢?

  • 理由1:IP 地址由网络服务商生成的逻辑地址,相对于 Mac 地址而言更容易控制和管理网络设备
  • 理由2:IP 地址有 IP 池、IP 段的概念,能通过 IP 地址来定位用户所在省、市、县域,而 Mac 地址是由厂商标识的,无法标记用户的位置信息,只能标记厂商信息

3.2、TCP 协议

TCP 协议是面向连接的传输层协议,每次连接都需要经过 3 个阶段:连接建立、数据传送和连接释放,即传输数据之前,在发送端和接收端建立逻辑连接、然后传输数据、最后断开连接,它保证了两台计算机之间可靠无差错的数据传输。

下面我们一起来看看 TCP 协议的报文格式,包含了哪些内容!

Java 网络编程总结(精华版)-鸿蒙开发者社区

TCP 报文段包括协议首部和数据两部分,协议首部的固定部分是 20 个字节,头部是固定部分,后面是选项部分。

下面是报文段首部各个字段的含义:

  • 源端口号以及目的端口号:各占 2 个字节,端口是传输层和应用层的服务接口,用于寻找发送端和接收端的进程,一般来讲,通过端口号和IP地址,可以唯一确定一个 TCP 连接,在网络编程中,通常被称为一个 socket 接口。
  • 序号:Seq 序号,占 4 个字节。用来标识从 TCP 发送端向 TCP 接收端发送的数据字节流序号,发起方发送数据时对此进行标记。
  • 确认序号:Ack 序号,占 4 个字节。包含接受端所期望收到的下一个序号。只有 ACK 标记位为 1 时,确认序号字段才有效,因此,确认序号应该是上次已经成功收到数据字节序号加 1,即 Ack = Seq + 1。
  • 数据偏移:占 4 个字节,用于指出 TCP 首部长度,若不存在选项,则这个值为 20 字节,数据偏移的最大值为 60 字节。
  • 保留字段:占 6 位,暂时可忽略,值全为 0。
  • 六位标志位:值内容含义如下
  • URG(紧急):为1时表明紧急指针字段有效
  • ACK(确认):为1时表明确认号字段有效
  • PSH(推送):为1时接收方应尽快将这个报文段交给应用层
  • RST(复位):为1时表明TCP连接出现故障必须重建连接
  • SYN(同步):在连接建立时用来同步序号
  • FIN(终止):为1时表明发送端数据发送完毕要求释放连接
  • 窗口:占 2 个字节,用于流量控制和拥塞控制,表示当前接收缓冲区的大小。
  • 校验和:占 2 个字节,范围包括首部和数据两部分
  • 紧急指针:指出了紧急数据的末尾在报文段中的位置,和 URG 搭配使用
  • 选项和填充:是可选的,默认情况是不选。

向深入的了解 TCP 原理的同学,可以看看这篇博客文章。

下面我们要重点说说 TCP 中的三次握手与四次挥手,因为这种数据传输模型保证了两台计算机之间可靠无差错的数据传输。

当两个设备之间准备传输时,TCP 会建立连接,创建连接的阶段需要三次握手,过程如下:

Java 网络编程总结(精华版)-鸿蒙开发者社区

  • 第一次握手:客户端向服务器端发出连接请求,等待服务器确认
  • 第二次握手:服务器端收到请求后,向客户端回送一个确认,通知客户端收到了连接请求
  • 第三次握手:客户端再次向服务器端发送确认信息,确认连接

完成以上 3 次握手之后,可靠性连接建立完成,准备进行数据传输。

当数据传输完毕之后,准备释放连接,连接的释放需要四次挥手,过程如下:

Java 网络编程总结(精华版)-鸿蒙开发者社区

  • 第一次挥手:客户端向服务器端发出请求切断连接,等待服务器确认
  • 第二次挥手:服务器端收到请求后,向客户端回送一个确认信息,并同意关闭请求
  • 第三次挥手:服务器端再次向客户端发出请求切断连接,等待客户端确认
  • 第四次挥手:客户端收到请求后,向服务器端回送一个确认信息,并同意关闭请求

完成以上 4 次挥手之后,连接释放完成。

3.3、UDP 协议

UDP 协议是 TCP/IP 协议簇中面向无连接的传输层协议,特点如下:

  • 1.传输数据之前,源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端,UDP 传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP 把每个消息段放在队列中,应用程序每次从队列中读一个消息段。
  • 2.由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务器可同时向多个客户端传输相同的消息。
  • 3.UDP 信息包的标题很短,只有 8 个字节,相对于 TCP 的 20 个字节信息包的额外开销很小。
  • 4.吞吐量不受拥挤控制算法的调节,只受应用软件生成数据的速率、传输带宽、源端和终端主机性能的限制。
  • 5.UDP 使用尽量最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的链接状态表
  • 6.UDP 是面向报文的。发送方的 UDP 对应用程序交下来的报文,在添加首部后就向下交付给 IP 层。既不拆分,也不合并,而是保留这些报文的边界,因此,应用程序需要选择合适的报文大小。

下面我们一起来看看 UDP 协议的报文格式,包含了哪些内容!

Java 网络编程总结(精华版)-鸿蒙开发者社区

UDP 协议由两部分组成:首部和数据。其中,首部仅有 8 个字节,包括源端口和目的端口、长度(UDP用于数据报的长度)、校验和。

UDP 协议没有像 TCP 协议那样的三次握手、四次挥手操作,数据传输模型非常简单,它只管发和收,总结下来,两者具体的区别如下:

  • 1.TCP 基于连接,UDP 是无连接的;
  • 2.对系统资源的要求,TCP 较多,UDP 较少
  • 3.UDP 程序结构较简单
  • 4.TCP 是流模式,而 UDP 是数据报模式
  • 5.TCP 保证数据正确性,而 UDP 可能丢包;TCP 保证数据顺序,而 UDP 不保证
  • 6.TCP 协议由于更安全、更可靠,应用场景比较广泛,例如上传文件、下载文件、浏览网页。
  • 7.UDP 协议虽然不可靠,但是传输效率更高,实际应用场景也比较多,例如视频会议、在线游戏、语音聊天等
  • 8.UDP 协议要求包小于 64K,TCP 没有限定

3.4、HTTP 协议

HTTP 协议,也俗称超文本传输协议,它是基于 TCP 协议之上的请求/响应式的应用层协议,使用 TCP/IP 来传输数据,也是互联网上应用最为广泛的一种网络协议。

HTTP 协议同时也是 Web 浏览器和 Web 服务器之间通信的标准协议。HTTP 指定客户端与服务器如何建立连接、客户端如何从服务器请求数据,服务器如何响应请求,以及最后如何关闭连接。

对于从客户端到服务器的每一个请求,都有 4 个步骤:

  • 1.默认情况下,客户端在端口 80 打开与服务器的一个 TCP 连接,不过 URL 中还可以指定其他端口。
  • 2.客户端向服务器发送消息,请求指定路径上的资源。这个资源包括一个首部,可选地(取决于请求的性质)还可以有一个空行,后面是这个请求的数据。
  • 3.服务器向客户端发送响应,响应以响应码开头,后面是包含数据的首部、一个空行以及所请求的文档或错误消息。
  • 4.服务器关闭连接。

现在使用的 HTTP 协议是 HTTP/1.1 版本,1997 年之前采用的是 HTTP/1.0 版本,两者区别在于:HTTP 连接在 1.0 版本中采用非持续连接工作方式,1.1 版本采用的是持续连接工作方式。持续连接是指服务器在发送响应后仍然在一段时间内保持这条由 TCP 传输层协议建立起来的连接,使客户端和服务器可以继续在这条连接上传输 HTTP 报文,避免重复的创建连接和释放连接。

是否采用持续连接工作方式,1.0 中默认是关闭的,需要在 HTTP 头加入​​Connection:Keep-Alive​​​,才能启用​​Keep-Alive​​​。HTTP1.1 中默认启用​​Keep-Alive​​​,如果加入​​Connection:close​​​,请求完会关闭连接。目前大部分浏览器都是用 HTTP1.1 协议,也就是说默认都会发起​​Keep-Alive​​​的连接请求了,是否能完成一个完整的​​Keep-Alive​​连接就看服务器设置情况。

下面我们一起来看看 HTTP 协议的报文格式,HTTP 报文主要包括:请求报文和响应报文两种。

HTTP 请求报文的格式如下:

Java 网络编程总结(精华版)-鸿蒙开发者社区

HTTP 请求报文由请求行、首部行和实体主体组成,由浏览器发送给服务器。上面这张图中 SP 表示空格,cr lf 表示回车和换行。下图是谷歌浏览器内访问服务器查看的 HTTP 请求报文例子:

Java 网络编程总结(精华版)-鸿蒙开发者社区

HTTP 响应报文的格式如下:

Java 网络编程总结(精华版)-鸿蒙开发者社区

上面这张图是 HTTP 响应报文,它由状态行、首部行和实体主体组成。下图是谷歌浏览器内访问服务器查看的 HTTP 响应报文例子:

Java 网络编程总结(精华版)-鸿蒙开发者社区

在上面的 HTTP 请求报文例子中,我们可以看到请求方法是 GET,它表示请求由 URL 所标志的信息,除了 GET,还有其他几种常用的方法。

Java 网络编程总结(精华版)-鸿蒙开发者社区

在 HTTP 响应报文的例子中,我们可以看到状态码是 200,表示响应成功,除此之外,还有其他的状态码,总共 5 大类。

Java 网络编程总结(精华版)-鸿蒙开发者社区

熟悉 HTTP 协议的同学可能都知道,HTTP 协议是以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了 Web 浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此 HTTP 协议不适合传输一些敏感信息,比如信用开号、密码等。

为了解决 HTTP 协议的这一缺陷,需要使用另一种协议:HTTPS 协议。

HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的 HTTP 通道,简单来说就是 HTTP 的安全版。即在 HTTP 下加入 SSL 协议,SSL 依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。

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

  • 1.http 是超文本传输协议,信息是明文传输;https 协议是由 http + ssl 协议构建的可进行加密传输、身份认证的网络协议,信息是密文传输,比 http 协议安全。
  • 2.https 协议需要到 ca 申请证书,一般免费证书很少,需要缴费
  • 3.http 和 https 使用的默认端口也不一样,前者是 80,后者是 443

更多的网络协议介绍,有兴趣的朋友可以看看这篇博客文章。

三、网络编程

看完以上信息之后,要想让网络中的计算机能够互相通信,少不了以下三个核心要素:

  • IP 地址:指的是计算机在网络中的唯一标识,目前使用最广泛的是 IPV4
  • 端口:指的是计算机中应用程序的唯一标识,用两个字节表示的整数,它的取值范围是​​0 - 65535​
  • 协议:指的是通过什么协议传输数据,例如 TCP、UDP

Java 语言对网络编程提供了良好的支持,通过其提供的接口我们可以很方便地进行网络编程。

下面我们一起来看看相关的代码实例!

3.1、URL 介绍

URL 表示统一资源定位符,指向万维网上“资源”的指针。

一个标准的 URL 包括以下几个部分:

  • protocol:方案或协议
  • host:主机或者 IP 地址
  • port:端口
  • path:路径
  • parameter:查询参数
  • anchor:锚点

在 www 上,每一信息资源都有统一且唯一的地址。

代码实例如下:

public static void main(String[] args) throws MalformedURLException {
    URL url = new URL("http://www.baidu.com:80/index.html?uname=dream&age=18#a");
    // 获取四个值:协议、域名、端口、请求资源
    System.out.println("协议:" + url.getProtocol());
    System.out.println("域名|IP:" + url.getHost());
    System.out.println("端口:" + url.getHost());
    System.out.println("请求资源:" + url.getPath());
    // 参数
    System.out.println("参数:" + url.getQuery());
    // 锚点
    System.out.println("锚点:" + url.getRef());
}

输出结果:

协议:http
域名|IP:www.baidu.com
端口:www.baidu.com
请求资源:/index.html
参数:uname=dream&age=18
锚点:a

3.2、InetAddress 介绍

为了方便我们对 IP 地址的获取和操作,Java 提供了一个类​​InetAddress​​供我们使用。

代码实例如下:

public static void main(String[] args) throws UnknownHostException {
    InetAddress address = InetAddress.getByName("www.baidu.com");
    System.out.println("主机名:" + address.getHostName());
    System.out.println("IP地址: " + address.getHostAddress());
}

输出结果:

主机名:www.baidu.com
IP地址: 14.119.104.254

3.3、IntetSocketAddress 介绍

IntetSocketAddress 包含 IP 和端口信息,常用于 Socket 通信。此类实现 IP 套接字地址(IP 地址+端口号),不依赖任何协议。

代码实例如下:

public static void main(String[] args){
    // 指定ip、端口
    InetSocketAddress socketAddress = new InetSocketAddress("14.119.104.254",80);
    System.out.println("主机名:" + socketAddress.getHostName());
    System.out.println("地址:" + socketAddress.getAddress());
    System.out.println("端口号:" + socketAddress.getPort());

    System.out.println("==================================");

    // 指定主机名、端口
    InetSocketAddress socketAddress2 = new InetSocketAddress("www.baidu.com",80);
    System.out.println("主机名:" + socketAddress2.getHostName());
    System.out.println("地址:" + socketAddress2.getAddress());
    System.out.println("端口号:" + socketAddress2.getPort());
}

输出结果:

主机名:14.119.104.254
地址:14.119.104.254/14.119.104.254
端口号:80
==================================
主机名:www.baidu.com
地址:www.baidu.com/14.119.104.254
端口号:80

3.4、Socket 介绍

Java 的网络编程主要涉及到的内容就是 Socket 编程。

Socket,也被称为套接字,它是网络通信中两台主机之间逻辑连接的端点的抽象表示,包含了进行网络通信必须的五种信息:连接使用的协议、本地主机的 IP 地址、本地进程的协议端口、远程主机的 IP 地址、远程进程的协议端口。

实际上,Socket 是对 TCP/IP 协议的封装实现,Socket 本身并不是协议,而是一个可以调用的接口(API);通过 Socket,程序员可以更方便地使用 TCP/IP 协议栈里面的逻辑,比如 create、accept、send、read 和 write 等等。

关于 Socket 和 TCP/IP 协议关系,如果感觉很抽象,你可以这样理解。TCP/IP 协议栈是网络信息传输的一个运行机制方案,而 Socket 是 TCP/IP 协议栈的具体技术编程实现。

Socket 编程主要涉及到客户端和服务端两个方面,以 TCP 协议通信为例,首先是在服务器端创建一个服务器套接字(ServerSocket),并把它附加到一个端口上,服务器从这个端口监听连接。端口号的范围是 0 到 65536,但是 0 到 1024 是为特权服务保留的端口号,在指定端口时尽量避开这个区间,我们可以选择一个当前没有被其他进程使用的端口。

客户端请求与服务器进行连接的时候,根据服务器的域名或者 IP 地址,加上端口号,打开一个 Socket 套接字。当服务器接受连接后,服务器和客户端之间的通信就可以像输入输出流一样进行操作。

Java 网络编程总结(精华版)-鸿蒙开发者社区

下面我们一起来看看具体的代码示例,更容易理解。

3.4.1、TCP 协议通信介绍

TCP 协议可以保证数据可靠、安全的传输给另一台主机,实际应用非常广泛,下面我们一起来看看如何实践。

首先创建一个服务端,代码实例如下:

public class ServerAdminTest {

    public static void main(String[] args) throws IOException {
        //使用需要捕获异常,因为可能会存在无法连接的情况
        ServerSocket serverSocket = new ServerSocket(8080);
        //测试语句
        System.out.println("本地服务器已开启");
        while (true){
            try {
                //等待客户端的连接
                Socket socket = serverSocket.accept();
                System.out.println("已收到客户机请求");

                //输入流,读取数据用的
                InputStream inputStream = socket.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

                //读取客户机发送来的消息,设置判断,只有客户机有发送消息才做输出语句
                String info;
                while((info = reader.readLine()) != null) {
                    System.out.println("收到客户机消息:"+info);
                }

                //输出流,发送数据用的
                OutputStream outputStream = socket.getOutputStream();
                PrintWriter printWriter = new PrintWriter(outputStream);

                //给客户机发送一段消息
                printWriter.write("hello,我是服务端,已收到你的信息!");
                printWriter.flush();

                //关闭输入、输出流
                reader.close();
                printWriter.close();

                //最后关闭网络连接
                socket.close();
            } catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

然后创建一个客户端,代码实例如下:

public class ClientAdminTest {

    public static void main(String[] args) throws IOException {
        //连接到目标服务器
        Socket client = new Socket("127.0.0.1",8080);
        System.out.println("客户机已经与服务器建立链接");

        //创建输出流
        OutputStream outputStream = client.getOutputStream();
        PrintWriter printWriter = new PrintWriter(outputStream);

        //输出这段话
        printWriter.write("hello,我是客户机!");
        printWriter.flush();

        //关闭输出,不再输出更多数据,如果不关闭,就会出现服务器无法判断客户机何时会结束发送消息,从而无法进行回应。就像一个人和你打电话的时候一直在说话,你无法在这段时间如回复他。
        client.shutdownOutput();

        //创建输入流
        InputStream inputStream = client.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

        //读取服务端发送过来的消息
        String info;
        while((info = reader.readLine()) != null) {
            System.out.println("接受服务器发送的消息:"+info);
        }

        //关闭输入、输出流
        reader.close();
        printWriter.close();

        //最后关闭网络连接,就和打完电话之后要挂断电话一样
        client.close();
    }
}

最后依次先后启动服务端、客户端,看看控制台输出结果如何。

服务端输出内容如下:

本地服务器已开启
已收到客户机请求
收到客户机消息:hello,我是客户机!

客户端输出内容如下:

客户机已经与服务器建立链接
接受服务器发送的消息:hello,我是服务端,已收到你的信息!

Socket 对 TCP/IP 协议里面的创建连接、释放连接进行了隐藏,开发者只需要关注数据传输即可。

3.4.2、UDP 协议通信介绍

UDP 协议是一种不可靠的网络协议,它在通信的两端各建立一个 Socket 对象,但是这两个 Socket 只是发送、接收数据的对象,没有客户端和服务器概念。

尽管如此,但是它传输速度高效,实际应用也非常广,下面我们一起来看看如何实践。

首先创建一个接受端,代码实例如下:

public class UDPReceive {

    public static void main(String[] args) throws IOException {
        System.out.println("接收方启动中...");
        // 1、创建接收端的Socket对象(DatagramSocket)
        DatagramSocket ds = new DatagramSocket(9999);

        // 2、创建一个数据包,用于接收数据
        byte[] bys = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bys, 0, bys.length);

        // 3、调用DatagramSocket对象的方法接收数据
        ds.receive(dp);

        // 4、解析数据包,并把数据在控制台显示
        System.out.println("数据是:" + new String(dp.getData(), 0, dp.getLength()));

        // 5、关闭接收端,释放资源
        ds.close();
    }
}

然后创建一个发送端,代码实例如下:

public class UDPSend {

    public static void main(String[] args) throws Exception {
        System.out.println("发送方启动中...");

        // 1、使用DatagramSocket指定端口,创建发送端
        DatagramSocket client = new DatagramSocket(8888);

        // 2、准备数据,一定要转成字节数组
        String data = "Java YYDS";

        // 3、封装成DatagramPacket包裹,需要指定目的地(IP+port)
        byte[] bys = data.getBytes();
        DatagramPacket packet = new DatagramPacket(bys, 0, bys.length, new InetSocketAddress("127.0.0.1", 9999));

        // 4、发送包裹 void send(DatagramPacket p)
        client.send(packet);

        // 5、释放资源
        client.close();
    }
}

最后依次先后启动接受端、发送端,看看控制台输出结果如何。

接受端输出内容如下:

接收方启动中...
数据是:Java YYDS

四、小结

本文主要是对网络编程做了一次知识内容总结,整合了网友分享的很多有价值的知识信息,希望能帮助到大家,内容难免有描述不对的地方,欢迎网友批评指出。


文章转载自公众号:Java极客技术


标签
已于2023-9-28 10:44:39修改
收藏
回复
举报
回复
    相关推荐