JAVA高级--网络编程

网络概述

计算机网络基础

在学习Java网络编程之前,我们先来了解什么是计算机网络。
计算机网络是指两台或更多的计算机组成的网络,在同一个网络中,任意两台计算机都可以直接通信,因为所有计算机都需要遵循同一种网络协议。
那什么是互联网呢?互联网是网络的网络(internet),即把很多计算机网络连接起来,形成一个全球统一的互联网。

网络通信协议

对某个特定的计算机网络来说,它可能使用网络协议ABC,而另一个计算机网络可能使用网络协议XYZ。如果计算机网络各自的通讯协议不统一,就没法把不同的网络连接起来形成互联网。因此,为了把计算机网络接入互联网,就必须使用TCP/IP协议。
TCP/IP协议泛指互联网协议,其中最重要的两个协议是TCP协议和IP协议。只有使用TCP/IP协议的计算机才能够联入互联网,使用其他网络协议(例如NetBIOS、AppleTalk协议等)是无法联入互联网的。

IP地址和端口

IP地址

在互联网中,一个IP地址用于唯一标识一个网络接口(Network Interface)。一台联入互联网的计算机肯定有一个IP地址,但也可能有多个IP地址 在网络编程中,可以使用IP或域名来标识网络上的一台设备。
IP地址分为IPv4和IPv6两种。IPv4采用32位地址,类似101.202.99.12,而IPv6采用128位地址,类似2001:0DA8:100A:0000:0000:1020:F2F3:1428。IPv4地址总共有232个(大约42亿),而IPv6地址则总共有2128个(大约340万亿亿亿亿),IPv4的地址目前已耗尽,而IPv6的地址是根本用不完的。
IP地址又分为公网IP地址和内网IP地址。公网IP地址可以直接被访问,内网IP地址只能在内网访问。
内网IP地址:

  • 192.168.1.1
  • 127.0.0.1

外网IP地址:

  • 220.181.38.150
  • 185.199.108.153

端口

为了在一台设备上可以运行多个程序,人为的设计了端口(Port)的概念,类似的例子是公司内部的分机号码。规定一个设备有216个,也就是65536个端口,每个端口对应一个唯一的程序。每个网络程序,无论是客户端还是服务器端,都对应一个或多个特定的端口号。由于0-1024之间多被操作系统占用,所以实际编程时一般采用1024以后的端口号。
下面是一些常见的服务对应的端口:

  • ftp:23
  • http:80
  • https:443
  • sqlserver:1433
  • mysql:3306
  • tomcat:8080

URL及其应用

URL(Uniform Resource Locator)中文名为统一资源定位符,有时也被俗称为网页地址。表示为互联网上的资源,如网页或者FTP地址

1
protocol://host:port/path?query#fragment

URL 解析:

  • 协议为(protocol):http
  • 主机为(host:port):www.runoob.com
  • 端口号为(port): 80 ,以上URL实例并未指定端口,因为 HTTP 协议默认的端口号为 80。
  • 文件路径为(path):/index.html
  • 请求参数(query):language=cn
  • 定位位置(fragment):j2se,定位到网页中 id 属性为 j2se 的 HTML 元素位置 。

构造方法:

常用方法:

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.net.*;
import java.io.*;

public class URLDemo{
public static void main(String [] args){
try{
URL url = new URL("http://www.fuxian.org/2020/03/10/java/Java%E4%B8%AD%E7%9A%84%E9%9B%86%E5%90%88%E6%A1%86%E6%9E%B6%E4%B8%8E%E6%B3%9B%E5%9E%8B/#more");
System.out.println("URL 为:" + url.toString());
System.out.println("协议为:" + url.getProtocol());
System.out.println("验证信息:" + url.getAuthority());
System.out.println("文件名及请求参数:" + url.getFile());
System.out.println("主机名:" + url.getHost());
System.out.println("路径:" + url.getPath());
System.out.println("端口:" + url.getPort());
System.out.println("默认端口:" + url.getDefaultPort());
System.out.println("请求参数:" + url.getQuery());
System.out.println("定位位置:" + url.getRef());
}catch(IOException e){
e.printStackTrace();
}
}
}

InetAddress及其应用

InetAddress在java.net包下,主要用于IP地址和域名
常用方法:

方法名说明
InetAddress getByName(String s) 获得一个InetAddress 类的对象,该对象中含有主机的IP地址和域名
String getHostName() 获取InetAddress对象的域名
String getHostAddress() 获取InetAddress对象的IP地址
InetAddress getLocalHost() 获得一个InetAddress对象,该对象含有本地机的域名和IP地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;

public class Test {
public static void main(String[] args) {
try {
InetAddress locAdd = InetAddress.getLocalHost(); // 得到本地InetAddress对象
InetAddress remAdd = InetAddress.getByName("www.fuxian.org"); // 取得远程InetAddress对象
System.out.println("本机IP地址:" + locAdd.getHostAddress()); // 得到本地IP地址
System.out.println("博客IP地址:" + remAdd.getHostAddress()); // 得到博客IP地址
System.out.println("博客域名:" + remAdd.getHostName()); // 得到博客域名

System.out.println("本机是否可达:" + locAdd.isReachable(10000)); // 10000是超时时间,10s
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

使用TCP协议的Socket

TCP 是传输控制协议的缩写,它保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP/IP
Socket套接字使用TCP提供了两台计算机之间的通信机制。 客户端程序创建一个套接字,并尝试连接服务器的套接字。
当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行通信
java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。

单向通信

首先建立服务器端Socket
步骤如下:

1
1:建立服务器端套接字,指定监听端口
2:监听,等待客户端请求,并愿意接受连接
3:获取Socket的输出流,并使用缓冲流进行包装
4:向客户端发送反馈信息
5:关闭流及Socket连接

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package Socket;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
public static void main(String[] args) {
Socket socket = null;
BufferedWriter writer = null;

try {
// 1:建立服务器端套接字,指定监听端口
ServerSocket ss = new ServerSocket(8888);
System.out.println("服务器建立监听中...");

// 2:监听,等待客户端请求,并愿意接受连接
socket = ss.accept();

// 3:获取Socket的输出流,并使用缓冲流进行包装
writer = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()));

// 4:向客户端发送反馈信息
writer.write(socket.getInetAddress().getHostAddress() + "客户端,你好!");
} catch (Exception e) {
e.printStackTrace();
} finally {
// 5:关闭流
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

}
}

再创建客户端Socket
创建步骤:

1
1:创建一个Socket对象
2:获取Socket的输入流,并使用缓冲流进行包装
3接收服务器端发送的信息
4:关闭流及Socket连接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package Socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

public class Client {
public static void main(String[] args) {
Socket socket = null;
BufferedReader read = null;

try {
// 1:创建一个Socket对象
socket = new Socket("127.0.0.1", 8888);

// 2:获取Socket的输入流,并使用缓冲流进行包装
read = new BufferedReader(new InputStreamReader(
socket.getInputStream()));

// 3:接收服务器端发送的信息

String line = read.readLine();
System.out.println("服务器:" + line);

} catch (Exception ex) {
ex.printStackTrace();
} finally {
// 4:关闭流及Socket连接
if (read != null) {
try {
read.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}

双向通信

双向通信就是服务器发送给客户端,客户端收到消息后也可以给服务器发送消息,服务器也能够收到消息

双向通信服务器端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package Socket;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class DoubleServer {
public static void main(String[] args) {
Socket socket = null;
BufferedWriter writer = null;
BufferedReader reader = null;
BufferedReader consoleIn = null;

try {
// 1:建立服务器端套接字,指定监听端口
ServerSocket ss = new ServerSocket(8888);
System.out.println("服务器建立监听中...");

// 2:监听,等待客户端请求,并愿意接受连接
socket = ss.accept();

// 3:获取Socket的输出流,并使用缓冲流进行包装
// 输出流-->我想客户端发送的内容
writer = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()));

// 输入流 -->客户端向我发送的内容
reader = new BufferedReader(new InputStreamReader(
socket.getInputStream()));

// 控制台输入流-->控制台向我发送的内容/控制台输入的内容
consoleIn = new BufferedReader(new InputStreamReader(System.in));

while (true) {
String fromClient = reader.readLine();// 读取输入流的内容(读取客户端向我发送的内容)
System.out.println("客户端说了:" + fromClient);

// 4:向客户端发送反馈信息
String toClient = consoleIn.readLine();// 读取控制台输入的内容
if (toClient.contains("end") || fromClient.contains("end"))
break;
writer.write(toClient + "\n");// 写入到输出流-->发送到客户端
writer.flush();// 刷新-->传输到客户端
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 5:关闭流
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (consoleIn != null) {
try {
consoleIn.close();
} catch (IOException e) {
e.printStackTrace();
}
}

if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}

}
}

双向通信客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package Socket;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class DoubleClient {
public static void main(String[] args) {
Socket socket = null;
BufferedWriter writer = null;
BufferedReader reader = null;
BufferedReader consoleIn = null;

try {
// 1:创建一个Socket对象
socket = new Socket("127.0.0.1", 8888);

// 2:获取Socket的输入流,并使用缓冲流进行包装
// 输出流 -->我向服务器端发送的内容
writer = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()));
// 输入流 -->服务器端向我发送的内容
reader = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
// 控制台输入流 -->控制台输入的内容
consoleIn = new BufferedReader(new InputStreamReader(System.in));

while (true) {
// 3:向服务器端发送反馈信息
String toServer = consoleIn.readLine();// 获取控制台输入流-->获取控制台输入的内容
if (toServer.contains("end")) {
break;
}
writer.write(toServer + "\n");// 写入输出流-->发送给服务器端的内容
writer.flush();// 刷新-->发送到服务器端

String fromServer = reader.readLine();// 获取输入流的内容-->获取服务器端发送给我的数据
System.out.println("服务器端说了:" + fromServer);// 显示数据
}

} catch (Exception ex) {
ex.printStackTrace();
} finally {
// 4:关闭流及Socket连接
// 5:关闭流
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (consoleIn != null) {
try {
consoleIn.close();
} catch (IOException e) {
e.printStackTrace();
}
}

if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

使用UDP协议建立通信

建立客户端

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class Client {
static Scanner sc = new Scanner(System.in);

public static void main(String[] args) throws IOException, InterruptedException {
// 1.创建客户端socket
DatagramSocket ds = new DatagramSocket();

while (true) {
System.out.println("请输入要发送的信息:");
String info = sc.nextLine();
byte[] buf = info.getBytes();
// 2.创建客户端发送数据包
// 3:将数据封装到数据包中,添加ip和端口以及数据
DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("localhost"), 8888);
// 4.发送数据包
ds.send(dp);
// 结束发送循环
if ("886".equals(info)) {
break;
}
}
// 5.关闭套接字
ds.close();
}
}

建立服务端:

package udpPackage;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

public class Server {

public static void main(String[] args) throws IOException {
// 1.创建服务端socket,并监听端口
DatagramSocket ds = new DatagramSocket(8888);// 注意指定端口
while (true) {
byte[] buf = new byte[1024];
// 2.创建数据包,用来接收数据
DatagramPacket dp = new DatagramPacket(buf, buf.length);
// 3.用socket接收数据到数据包中
ds.receive(dp);
// 4.读取数据
String info = new String(buf, 0, buf.length);
System.out.println("消息是:" + info);
if ("886".equals(info))
break;
}
// 5:关闭资源
ds.close();
}

}

 

posted @ 2020-07-31 20:58  大可耐啊  阅读(43)  评论(0)    收藏  举报