Java网络编程

Java网络编程

  • 网络编程三要素:

    • IP地址:InetAddress: 网络中设备的标识,不易记忆,可用主机名

    • 端口号:用于标识进程的逻辑地址

    • 传输协议:通讯的规则常见协议:TCP,UDP

1、IP地址:InetAddress

  • 唯一的标识Internet上的计算机(通信实体)

  • 本地回环地址:127.0.0.1(主机名:localhost)

  • IP地址分类:IPV4和IPV6

  • IP地址分类方式2:公网地址(万维网使用)和私有地址(局域网使用)。192.168.开头就是私有地址,范围为192.168.0.0—192.168.255.255,专门为组织机构使用

  • 特点:不易记忆

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @Test
    public void test1() {
    try {
    //实例化InetAddress对象
    InetAddress add1 = InetAddress.getByName("192.168.10.14");//根据ip实例化
    System.out.println(add1); //输出:/192.168.10.14
    InetAddress add2 = InetAddress.getByName("www.baidu.com");//根据域名实例化
    System.out.println(add2); //输出:www.baidu.com/180.101.49.12
    //获取对应ip:getHostAddress()
    System.out.println(add2.getHostAddress());
    //获取对应域名:getHostName()
    System.out.println(add2.getHostName());
    //获取本机的ip
    InetAddress localHost = InetAddress.getLocalHost();
    System.out.println(localHost);
    } catch (UnknownHostException e) {
    e.printStackTrace();
    }
    }

2、端口号

  • 端口号标识正在计算机上运行的程序(进程)
  • 端口号的范围:0~65535
  • 端口分类:
    • 公认端口:0~1023。被预先定义的服务通信占用(如HTTP占用端口80,FTP占用端口21,Telnet占用端口23)
    • 注册端口:1024~49151。分配给用户进程或应用程序(如Tomcat占用端口8080,Mysql占用端口3306等)
    • 动态/私有端口:49152~65535
  • 端口号与IP地址的组合得出一个网络套接字:Socket。

3、网络协议

3.1、TCP/IP协议簇:

  • 传输层协议中有两个重要的协议:
    • 传输控制协议TCP(Transmission Control Protocol)
    • 用户数据报协议UDP(User Datagram Protocol)
  • TCP/IP以其两个主要协议:传输控制协议(TCP)和网络互联协议(IP)而得名,实际上是一组协议,包括多个具有不同功能且互为关联的协议。
  • IP(Internet Protocol)协议是网络层的主要协议,支持网间互联的数据通信。
  • TCP/IP协议模型从更实用的角度出发,形成了高效的四层体系结构,即:物理链路层、IP层、传输层和应用层。

3.2、UDP协议与TCP协议的区别:

  • UDP协议——发短信
    • 将数据、源和目的封装成数据包中,不需要建立连接
    • 每个数据报的大小在限制在64k内;
    • 发送不管对方是否准备好,接收方收到也不确认,故不可靠
    • 可以广播发送
    • 发送数据结束时无需释放资源,开销小,速度快
  • TCP协议——打电话、视频
    • 使用前必须先建立TCP连接,形成传输数据的通道;
    • 传输前使用”三次握手“方式,点对点通信,是可靠的
    • TCP协议进行通信的两个应用进程:客户端、服务端
    • 在连接中可进行大数据量的传输
    • 传输完毕,需要释放已建立的连接,效率低

4、TCP网络编程

4.1、模拟客户端给服务端发送消息,服务端接收消息:

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
87
88
89
90
91
92
93
94
95
//注意:先运行服务端,再运行客户端,否则客户端报错(因为TCP协议需要建立连接)
//客户端
@Test
public void client() {
Socket socket = null;
OutputStream outputStream = null;
try {
InetAddress ip = InetAddress.getByName("127.0.0.1"); //服务端的IP
//IP + 端口号,指明要和客户端通信的服务器
socket = new Socket(ip, 8848);
//获取流
outputStream = socket.getOutputStream();
//通过流发送消息
outputStream.write("你好!这是客户端发送的一条数据。".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//服务端
@Test
public void server() {
ServerSocket serverSocket = null;
InputStream inputStream = null;
Socket socket = null;
ByteArrayOutputStream stream = null;
try {
//开启自己的端口
serverSocket = new ServerSocket(8848);
//接收来自客户端的Socket
socket = serverSocket.accept();
//获取流
inputStream = socket.getInputStream();
//这样写可能会有乱码问题
//byte[] bytes = new byte[1024];
//int len;
//while ((len = inputStream.read(bytes))!=-1){
// String s = new String(bytes, 0, len);
// System.out.println(s);
//}
stream = new ByteArrayOutputStream();
byte[] bytes = new byte[5];
int len;
while ((len = inputStream.read(bytes)) != -1) {
//写入收到的消息
stream.write(bytes, 0, len);
}
System.out.println("收到了来自" + socket.getInetAddress().getHostName()
+ "的消息:" + stream.toString());
//输出结果:收到了来自127.0.0.1的消息:你好!这是客户端发送的一条数据。
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
try {
if (serverSocket != null)
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (inputStream != null)
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (stream != null)
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

4.2、模拟客户端给服务端发送文件,服务端接收文件:

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
//此处为了代码结构清晰,所以直接throws异常
//注意:先运行服务端,再运行客户端,否则客户端报错(因为TCP协议需要建立连接)
//客户端发送1.jpg
@Test
public void client() throws IOException {
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),8888);
OutputStream outputStream = socket.getOutputStream();
FileInputStream fileInputStream = new FileInputStream("1.jpg");
byte[] bytes = new byte[1024];
int len;
while ((len = fileInputStream.read(bytes))!=-1){
outputStream.write(bytes,0,len);
}
socket.close();
fileInputStream.close();
outputStream.close();
}
//服务端接收并另存为2.jpg
@Test
public void server() throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
FileOutputStream fileOutputStream = new FileOutputStream("2.jpg");
byte[] bytes = new byte[1024];
int len;
while ((len = inputStream.read(bytes))!=-1){
fileOutputStream.write(bytes,0,len);
}
serverSocket.close();
socket.close();
inputStream.close();
fileOutputStream.close();
}

4.3、模拟客户端给服务端发送文件,服务端接收文件,并且给予客户端反馈,客户端接收反馈并打印反馈信息:

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
//此处为了代码结构清晰,所以直接throws异常
//注意:先运行服务端,再运行客户端,否则客户端报错(因为TCP协议需要建立连接)
//客户端发送1.jpg,且接收服务端的反馈信息
@Test
public void client() throws IOException {
FileInputStream fileInputStream = new FileInputStream("1.jpg");
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 8999);
OutputStream outputStream = socket.getOutputStream();
byte[] bytes = new byte[1024];
int len;
//输入流将文件1.jpg读入内存
while ((len = fileInputStream.read(bytes)) != -1) {
//输出流将读入内存的文件写出
outputStream.write(bytes, 0, len);
}
//关闭数据的输出
socket.shutdownOutput();
//客户端接收反馈,打印
InputStream inputStream = socket.getInputStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] bytes1 = new byte[5];
int len1;
//输入流将反馈信息读入
while ((len1 = inputStream.read(bytes1)) != -1) {
//输出流将反馈信息写出
byteArrayOutputStream.write(bytes1, 0, len1);
}
System.out.println(byteArrayOutputStream.toString());//打印结果:服务器已经接收文件!

socket.close();
fileInputStream.close();
outputStream.close();
inputStream.close();
byteArrayOutputStream.close();
}

//服务端接收并保存为2.jpg,且给予反馈信息
@Test
public void server() throws IOException {
ServerSocket serverSocket = new ServerSocket(8999);
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
FileOutputStream fileOutputStream = new FileOutputStream("2.jpg");
byte[] bytes = new byte[1024];
int len;
//将接收的文件读入内存
while ((len = inputStream.read(bytes)) != -1) {
//将刚读入的文件从内存写出
fileOutputStream.write(bytes, 0, len);
}
//服务器端给予反馈
OutputStream outputStream = socket.getOutputStream();
outputStream.write("服务器已经接收文件!".getBytes());

serverSocket.close();
socket.close();
inputStream.close();
outputStream.close();
fileOutputStream.close();
}

5、UDP网络编程

5.1、发送端发送数据,接收端接收数据

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
//此处为了代码结构清晰,所以直接throws异常
//注意:先运行接收端,后运行发送端
//反过来虽然不报错(因为UDP协议不需要建立连接),但是收不到数据
//发送端
@Test
public void sender() throws Exception {
DatagramSocket socket = new DatagramSocket();
String str = "我是UDP发送的数据";
byte[] data = str.getBytes(); //发送的数据
InetAddress ip = InetAddress.getByName("127.0.0.1");//指明对方IP
//封装一个数据包
DatagramPacket packet = new DatagramPacket(data, 0, data.length, ip, 8848);
//发送数据包
socket.send(packet);
//关闭socket
socket.close();
}

//接收端
@Test
public void receiver() throws Exception {
//接收端需要指明自己的端口号
DatagramSocket socket = new DatagramSocket(8848);
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
//将数据接收到数据包中
socket.receive(packet);
System.out.println(new String(packet.getData(), 0, packet.getLength()));
socket.close();
}

6、URL编程

  • URL(Uniform Resource Locator):统一资源定位符,它表示Internet上某一资源的地址
  • 它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源
  • URL的基本结构由5部分组成:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Test
public void Test(){
try {
URL url = new URL("http://localhost:8080/shop/index.html?username=Tom");
//协议名
System.out.println(url.getProtocol()); //输出:http
//主机名
System.out.println(url.getHost()); //输出:localhost
//端口
System.out.println(url.getPort()); //输出:8080
//文件路径
System.out.println(url.getPath()); //输出:/shop/index.html
//文件名
System.out.println(url.getFile()); //输出:/shop/index.html?username=Tom
//参数列表
System.out.println(url.getQuery());//输出:username=Tom
} catch (Exception 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
//从服务器下载资源(先要开启tomcat服务器,并且有对应的资源)
@Test
public void Test() {
HttpURLConnection connection = null;
InputStream inputStream = null;
FileOutputStream fileOutputStream = null;
try {
URL url = new URL("http://localhost:8080/hello/1.jpg");
connection = (HttpURLConnection) url.openConnection();
connection.connect();
inputStream = connection.getInputStream();
fileOutputStream = new FileOutputStream("3.jpg");
byte[] bytes = new byte[1024];
int len;
while ((len = inputStream.read(bytes)) != -1) {
fileOutputStream.write(bytes, 0, len);
}
System.out.println("下载完成");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null)
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fileOutputStream != null)
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
if (connection != null)
connection.disconnect();
}
}