javaSE基础-网络编程
网络编程
网络编程概述
java提供的网络库,可以实现自由的网络连接,联网的底层细节被隐藏在Java本机安装系统里,由JVM进行控制。并且Java实现了一个跨平台的网络库,编程人员使用的是统一的网络编程环境
计算机网络
把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息、共享硬件、软件、数据信息等资源
目的:直接或间接地通过网络协议与其他计算机实现数据交互,进行通讯
两个主要的问题
- 如何准确地定位网络上一台或多台主机,定位主机上的特定的应用
- 找到主机后如何可靠高效地进行数据传输
网络通信要素概述
通信双方地址
- IP:解决准确定位主机问题
- 端口号:解决定位应用问题
一定的规则(即网络通信协议)
- OSI参考模型:过于理想化,未在英特网推广
- TCP/IP参考模型(也叫TCP/IP协议):当前英特网的国际标准
网络通信协议模型
网络通信协议:计算机网络中实现通信必须有一些约定,即通信协议,对速率、传输代码、代码结构、传输控制步骤、出错控制等指定标准
域名解析
域名容易记忆,在连接网络时输入一个主机的域名后,在域名服务器(DNS)负责将域名转化成IP地址,这样才能与主机建立联系
通信协分层的思想
在制定协议时,把复杂成分分解成一些简单的成分,再将它们复合起来。最常用的复合方式是层次方式,即同层间可以通信、上一层可以调用下一层,而与下一层不发生关系。各层互不影响,有利于系统的开发与拓展
网络通信数据传输示意图
通信要素简介
IP地址(InetAddress)
- 唯一的标识Internet上的计算机(通信实体)
- 本地回环地址(hostAddress):127.0.0.1 主机名(hostName):localhost
- IP地址分类方式一:IPV4 和 IPV6
- IPV4:4个字节组成,4个0~255.大概有42亿。以点分十进制表示:如192.168.0.1
- IPV6:128位(16个字节),写成8个无符号整数,每个整数用四个十六进制位表示,数之间用冒号(:)分开,如:ABCD:EF01:2345:6789:ABCD:EF01:2345:6789
- IP地址分类方式二:公网地址(万维网使用)和私有地址(局域网使用)。192.168开头的就是私有地址,范围即为192.168.0.0~192.168.255.255,专门组织机构内部使用
端口号
标识正在计算机上运行的进程
- 不同的进程有不同的端口号
- 被规定为一个16位的整数0~65535
- 端口分类
- 公认端口:0~1023.被预先定义的服务通信占用(HTTP占用端口80,FTP占用端口21,Telnet占用端口23)
- 注册端口:1024~49151。分配给用户进程或应用程序。(Tomcat端口8080,MySQL端口3306,Oracle端口1521)
- 动态/私有端口:49152~65535
- IP地址:端口号 = 网络套接字Socket
TCP/IP协议簇
传输层协议中两个重要协议
- 传输控制协议TCP(Transmission Control Protocol)
- 用户数据报协议UDP(User Datagram Protocol)
TCP/IP 以其两个主要协议:传输控制协议(TCP)和网络互联协议(IP)而得名,实际上是一组协议,包括多个具有不同功能且互为关联的协议
- IP(Internet Protocol)协议是网络层的主要协议,支持网间互连的数据通信
- TCP/IP协议模型从更实用的角度出发,形成高效的四层体系结构,即物理链路层、IP层、传输层和应用层
TCP和UDP特点
TCP协议
- 使用TCP协议前,须先建立TCP连接,形成传输数据通道
- 传输前,采用“三次握手”方式,点对点通信,是可靠的
- TCP协议进行通信的两个应用进程:客户端 、服务器
- 在连接中进行大数据量的传输
- 传输完毕,需要释放已建立的连接,效率低
UDP协议
- 将数据、源、目的封装成数据包,不需要建立连接
- 每个数据报大小限制在64k内
- 发送不管对方是否准备好,接收方收到也不确认,故是不可靠的
- 可以广播发送
- 发送数据结束时,无需释放资源,开销小,速度快
TCP建立连接过程示意图
TCP断开连接过程示意图
TCP网络编程
InetAddress类:此类的一个对象代表着一个具体的IP地址
构造器
getByName(String host) / getLocalHost()
常用方法
getHostName() / getHostAddress()
public class NetWorkTest {
public static void main(String[] args) throws UnknownHostException {
InetAddress inet1 = InetAddress.getByName("192.168.1.1");
System.out.println(inet1);
System.out.println(inet1.getHostName());
System.out.println(inet1.getHostAddress());
InetAddress inet2 = InetAddress.getByName("www.baidu.com");
System.out.println(inet2);
}
}
客户端向服务器发送一条信息
click me
public class TCPTest {
//客户端
@Test
public void client(){
Socket socket = null;
OutputStream os = null;
try {
//1、创建Socket,指明服务器端的IP和端口
InetAddress address = InetAddress.getByName("localhost");
socket = new Socket(address, 8081);
//2、获取数据输出流
os = socket.getOutputStream();
//3、写出数据
os.write("这是一个客户端。".getBytes());
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
//4、关闭资源
if(os != null){
try {
os.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(socket != null){
try {
socket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
//服务器
@Test
public void server() {
ServerSocket ss = null;
Socket socket = null;
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
//1、创建ServerSocket,指明本身的端口
ss = new ServerSocket(8081);
//2、调用accept(),接受客户端信息
socket = ss.accept();
//3、获取输入流
is = socket.getInputStream();
//4、读取流中数据
//方式一:有可能出现乱码,不建议使用
//byte[] buffer = new byte[20];
//int len;
//while ((len = is.read(buffer)) != -1){
// String str = new String(buffer, 0, len);
// System.out.print(str);
//}
//方式二
baos = new ByteArrayOutputStream();//该字节数组临时存储字节信息
byte[] buffer = new byte[10];
int len;
while ((len = is.read(buffer)) != -1){
baos.write(buffer, 0 ,len);
}
System.out.println("信息:" + baos.toString());
System.out.println("收到来自于 " + socket.getInetAddress().getHostAddress() + " 的数据");
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
//5、关闭资源
if(baos != null){
try {
baos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(is != null){
try {
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(socket != null){
try {
socket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(ss != null){
try {
ss.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
从客户端向服务器传输文件,并将文件保存到本地,同时向客户端反馈"发送成功"信息,并关闭相应的连接
click me
public class TCPTest3 {
//客户端
@Test
public void client() throws IOException {
Socket socket = new Socket(InetAddress.getByName("localhost"), 8899);
OutputStream os = socket.getOutputStream();
FileInputStream fis = new FileInputStream(new File("omni.png"));
byte[] buffer = new byte[1024];
int len;
while((len = fis.read(buffer)) != -1){
os.write(buffer, 0, len);
}
socket.shutdownOutput();//在执行下一次数据传输之前,需要把本次输出流关闭
//接受服务器的信息,并输出到控制台
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer2 = new byte[10];
int len2;
while((len2 = is.read(buffer2)) != -1){
baos.write(buffer2, 0 ,len2);
}
System.out.println(baos.toString());
fis.close();
os.close();
socket.close();
baos.close();
is.close();
}
//服务器
@Test
public void server() throws IOException {
ServerSocket ss = new ServerSocket(8899);
Socket socket = ss.accept();
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream(new File("omni3.png"));
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1){
fos.write(buffer, 0 ,len);
}
System.out.println("图片保存成功。。。");
//服务器向客户端反馈成功信息信息
OutputStream os = socket.getOutputStream();
os.write("你好,图片传输成功了,谢谢!".getBytes());
fos.close();
is.close();
socket.close();
ss.close();
os.close();
}
}
UDP网络编程
DatagramSocket():该方法发送和接收UDP的数据报
DatagramPacket():封装UDP数据报的信息,包含发送端和接收端的ip、端口
两个方法:
send(): 发送数据报
receive():接收数据报
public class UDPTest {
@Test
public void sender() throws IOException {
DatagramSocket socket = new DatagramSocket();
String str = "这是一个数据包,UDP方式传输。";
byte[] buffer = str.getBytes();
InetAddress inet = InetAddress.getLocalHost();
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length, inet, 9089);
socket.send(packet);
socket.close();
}
@Test
public void receiver() throws IOException {
DatagramSocket socket = new DatagramSocket(9089);
byte[] buffer = new byte[100];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(packet);
byte[] data = packet.getData();
//将接收的字节数组转换为String,输出都控制台
System.out.println(new String(data, 0, packet.getLength()));
socket.close();
}
}
URL编程
URI全称为Uniform Resource Identifier,统一资源标识符,作用是标识某一互联网资源。
URL全称为Uniform Resource Locator,统一资源定位符,用于表示资源的地点。
URI与URL的联系是它们都能够唯一地确定一个资源,区别是URL是通过资源的地点来确定资源的。因此,可以说URL是URI的子集。
URI格式
URI没有非常具体的格式,一般由模式和模式特定部分组成,模式特定部分的语法取决于所用的格式,如下:
模式:模式特定部分[#片段标识符]
模式类型
data:Base64编码数据
file:本地磁盘上的文件
ftp:FTP服务器
http:使用HTTP的国际互联网服务器
mailto:电子邮件地址
magnet:可通过对等网络(BT等)下载的资源
telnet:与基于Telnet的服务的连接
urn:统一资源名(Uniform Resource Name,URN)
除了这些标准模式,Java还支持rmi,jar,jndi,doc等非标准的定制模式,用于实现不同用途。
模式特定部分没有特定的语法,一般会采用一种层次结构形式,如下:
//authorith/path?query
其中authority为授权机构,负责解析URI其余部分,path为路径,query为查询字符串。
URL格式
https://localhost:8080/posts/1503359168.html?user=Jom
协议 主机名 端口号 资源地址 参数列表
常用方法
public class URLTest {
public static void main(String[] args) {
try {
URL url = new URL("https://localhost:8080/posts/1503359168.html?user=Jom");
System.out.println("获取URL的协议名:" + url.getProtocol());
System.out.println("获取URL的主机名:" + url.getHost());
System.out.println("获取URL的端口号:" + url.getPort());
System.out.println("获取URL的文件路径:" + url.getPath());
System.out.println("获取URL的文件名:" + url.getFile());
System.out.println("获取URL的查询名:" + url.getQuery());
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
}
使用URL下载url资源
public class URLDownload {
public static void main(String[] args) throws IOException {
URL url = new URL("https://i0.hdslb.com/bfs/article/4a55973456411373435f6f805edd2a8cf1a20b6c.jpg@942w_1395h_progressive.webp");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
//url连接
urlConnection.connect();
InputStream is = urlConnection.getInputStream();
FileOutputStream fos = new FileOutputStream("二次元.jpg");
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
System.out.println("下载成功!");
//关闭资源,并断开url连接
fos.close();
is.close();
urlConnection.disconnect();
}
}