Java 19 网络编程、UDP编程、TCP编程、粘包问题、文件上传

一、网络编程概述

1、基本概述

计算机可以通过网络连接,组成计算机网络,计算机之间可以通过网络进行通信,传递信息。很多程序也都具有网络通信能力。而java也提供了网络开发的能力,这称之为java的网络编程。

2、网络模型

一般指为OSI七层网络模型TCP/IP四层参考模型

OSI七层网络模型

物理层 -> 数据链路层 -> 网络层 -> 传输层 -> 会话层 -> 表示层 -> 网络层

3、网络协议

网络中的计算机想要互相通信,必须遵循相同的沟通方式,需要提前约定,这样提前约定的沟通方式,称之为网络协议。

由于网络是分层的,每层之间都有数据要传递,一般的协议都是为某一个层数据的通信来订立的,所以一般来说一个协议通常是归属于某一层的,每一个层也有若干的协议来约定通信规则。

协议也可以分为公有协议个私有协议。

公有协议是由国际化标准组织订立的,全世界的计算机都去遵循。

应用层:HTTP HTTPS FTP SMTP POP3

传输层:TPC UDP

网络层:IP协议

私有协议是公司、组织、团队、个人自己约定的协议、只在遵循该协议的小范围内起作用。

4、IP协议

IP协议目前有两个版本:

IPV4

是由32位二进制数来表示的地址,通常被分割为4个8位二进制数

0~255.0~255.0~255.0~255

以下网段比较特殊,是内网地址

10.0.0.0~10.255.255.255

172.16.0.0~172.16.255.255

192.168.0.0~196.168.255.255

特殊的IP地址

是由128位的二进制数表示的地址,可以表示2^128个地址

5、端口

每个计算机除了可以分配到一个IP以外还会划分出2^16个端口。

需要网络通信的软件可以来占用一个端口,通过[IP:端口]在指定ip的指定端口上进行通信。

虽然IP只有一个,但是端口有很多,所以可以在一个IP上利用不同端口实现同时进行多个通信的效果。

端口的范围是:0~65535

其中0~1024的端口是计算机预留的端口,普通程序不可以占用。其他端口应用程序随便占用,先到先得,同一时间一个端口只能有一个程序占用,所以用完后端口会被释放,其他程序才可以再次占用。

6、主机名 域名 DNS服务器 Hosts文件

主机名:

IP地址可以表示网络中的主机,但是IP不易记忆,所以一般都会选择为当前主机指定主机名。

域名:

主机名是可能重复的,为了防止在公网上主机名重复,有了域名的概念,域名需要统一到域名管理组织中注册,从而防止重复。

DNS域名服务器:

网络中有 DNS服务器中可以帮我们将主机名或域名翻译成对应IP。

Hosts文件:

可以在本地的Hosts文件中模拟DNS的功能

Windows下:

C:\Windows\System32\drivers\etc\Hosts

Linux下:

/etc/hosts

7、套接字编程 Socket编程

为了能够使开发人员开发网络相关的程序,操作系统为开发者提供了网络编程的接口,通过这套接口可以开发基于网络层和传输层的代码从而实现网络通信。

物理层和数据链路层由操作系统负责,不需要开发人员关注,会话层、表示层 、应用层当中的需求则需要开发人员根据需要自己来实现。

这套操作系统提供的网络编程的接口称之为Socket - 套接字编程。

套接字不是协议,只是一套编程接口。

二、java网络开发 — IP地址

1、代表IP地址的类

public classInetAddressextends Object implements Serializable

重要方法:

static InetAddressgetByAddress(byte[] addr)

在给定原始 IP 地址的情况下,返回 InetAddress 对象。

static InetAddressgetByName(String host)

在给定主机名的情况下确定主机的 IP 地址。

static InetAddressgetLocalHost()

返回本地主机。

StringgetHostAddress()

返回 IP 地址字符串(以文本表现形式)。

StringgetHostName()

获取此 IP 地址的主机名。

byte[]getAddress()

返回此 InetAddress 对象的原始 IP 地址。

public classInetSocketAddressextends SocketAddress

此类实现 IP 套接字地址(IP 地址 + 端口号)。它还可以是一个对(主机名 + 端口号),在此情况下,将尝试解析主机名。如果解析失败,则该地址将被视为未解析 地址,但是其在某些情形下仍然可以使用,比如通过代理连接。

构造方法:

InetSocketAddress(InetAddress addr, int port)

根据 IP 地址和端口号创建套接字地址。

InetSocketAddress(int port)

创建套接字地址,其中 IP 地址为通配符地址,端口号为指定值。

InetSocketAddress(String hostname, int port)

根据主机名和端口号创建套接字地址。

重要方法:

InetAddressgetAddress()

获取 InetAddress。

StringgetHostName()

获取 hostname。

intgetPort()

获取端口号。

三、Socket编程 — UDP编程

1、UDP协议概述

UDP是TCP协议中非常重要和常用的通信协议,可以实现不可靠的网络通信。

特点:

速度比较快。

不需要创建连接。

数据以独立的数据包的形式发送,每个数据包最大64KB

传输过程中不保证数据一定可以到达,也不保证接受的到的数据包的顺序和发送时一致

类似于飞鸽传书,在速度要求比较高、可靠性要求比较低的场景下优先使用。

2、java中UDP的实现

public classDatagramSocketextends Object

此类表示用来发送和接收数据报包的套接字。代表UDP通信的一个端

构造方法:

DatagramSocket()

构造数据报套接字并将其绑定到本地主机上任何可用的端口。

DatagramSocket(int port)

创建数据报套接字并将其绑定到本地主机上的指定端口。

DatagramSocket(SocketAddress bindaddr)

创建数据报套接字,将其绑定到指定的本地套接字地址。

重要方法:

voidreceive(DatagramPacket p)

从此套接字接收数据报包。

voidsend(DatagramPacket p)

从此套接字发送数据报包。

voidclose()

关闭此数据报套接字。

public final classDatagramPacketextends Object

此类表示数据报包。

构造方法:

DatagramPacket(byte[] buf, int length)

构造 DatagramPacket,用来接收长度为 length 的数据包。

重要方法:

byte[]getData()

返回数据缓冲区。

intgetLength()

返回将要发送或接收到的数据的长度。

SocketAddressgetSocketAddress()

获取要将此包发送到的或发出此数据报的远程主机的 SocketAddress(通常为 IP 地址 + 端口号)。

voidsetData(byte[] buf)

为此包设置数据缓冲区。

四、Socket编程 — TCP编程

1、TCP协议概述

TCP是TCP协议中非常重要和常用的通信协议,可以实现可靠的网络通信。

特点:

速度比较慢。

需要创建连接,需要三次握手

底层建立的连接流,数据包以流的方式传递,没有传输数据量大小的限制

传输过程中可以保证数据一定不会丢也不会多,也可以保证顺序的一致

在可靠性要求比较高,速度要求比较低的场景下优先使用。

2、java中TCP的实现

在TCP通信中,通信的过程需要两端的参与,其中发起请求的端称之为客户端,被动等待请求的端称之为服务器端

public classSocketextends Object

此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。代表TCP通信中的客户端的类。

构造方法:

Socket()

通过系统默认类型的 SocketImpl 创建未连接套接字。

Socket(InetAddress address, int port)

创建一个流套接字并将其连接到指定 IP 地址的指定端口号。

Socket(String host, int port)

创建一个流套接字并将其连接到指定主机上的指定端口号。

普通方法:

voidconnect(SocketAddress endpoint)

将此套接字连接到服务器。

InputStreamgetInputStream()

返回此套接字的输入流。

OutputStreamgetOutputStream()

返回此套接字的输出流。

voidclose()

关闭此套接字。

public classServerSocketextends Object

构造方法:

ServerSocket()

创建非绑定服务器套接字。

ServerSocket(int port)

创建绑定到特定端口的服务器套接字。

普通方法:

voidbind(SocketAddress endpoint)

将ServerSocket 绑定到特定地址(IP 地址和端口号)。

Socketaccept()

侦听并接受到此套接字的连接。

voidclose()

关闭此套接字。

3、在TCP网络通信中应用多线程技术实现一个服务端为多个客户端提供服务

4、TCP通信中的粘包问题

a.粘包问题概述

TCP通信中,如果连续传输多段数据,TCP在传输的过程中,会根据需要自动的拆分包合并包,造成数据边界信息丢失,在接收端收到数据后无法判断数据的边界在哪里,这样的问题就称之为TCP通信中的粘包问题。

粘包问题的本质在于TCP协议是传输层的协议,而数据边界判断的问题本质上是会话层的问题,TCP协议并没有给予解决方案。

而Socket编程是基于网络层和传输层的编程,没有会话层的功能提供,所以在Socket编程中粘包问题需要程序开发人员自己想办法解决。

b.粘包问题解决方案

i.只传输固定长度的数据

能解决粘包问题,但是程序的灵活性非常低,只能在每次传输的数据长度都一致的情况下使用,应用的场景比较少

ii.约定分隔符

能解决粘包问题,但是如果数据本身包含分隔符,则需要进行转义。转义的过程比较麻烦,浪费时间,代码写起来也比较复杂

iii.使用协议

在通信双发原定数据传输的格式,发送方严格按照格式发送,接收方严格按照格式接收,从而根据格式本身判断数据的边界。

协议又分为公有协议和私有协议

使用公有协议:

利用会话层、表示、应用层的公有协议的规则,来传输数据,判断边界

在全世界范围内通用,但协议相对复杂。

使用私有协议:

自己来约定传输双方使用的格式,从而来判断边界,协议可以根据需要定制,但只在有限的小范围内有效。

五、案例

文件上传案例,通过自定义协议解决粘包问题,实现传输文件同时传输文件名。

图示理解:

代码演示:

客户端代码

服务端代码

内容仅供个人学习记录使用,侵删

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180828G1XYLA00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券