135. 网络编程

概述

地球村:现代科技缩小世界的时空距离

信件 ——> 网络编程

计算机网络

计算机网络是指将地理位置不同的具有独立功能的多台计算机机器外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及光网络通信协议(类似于方言、语言)的管理和协调下,实现资源共享和信息传递的计算机系统。

网络编程的目的

无线电台… :传播交流信息,数据交换。(通信

想要达到这个效果需要什么

  1. 如何准确的定位网络上的一台主机 :192.168.16.124:port,定位到这个计算机上的某个资源
  2. 找到了这个主机,如何传输数据呢?

javaweb: 网页编程 B/S架构

网络编程: TCP/IP

网络通信的要素

如何实现网络的通信?

通信双方的地址

  • ip (唯一(指的是公网,不是局域网))
  • port
  • 192.168.16.124:5900ip:port):就可以定位到某台计算机上的某一个应用

规则:网络通信的协议

http, ftp, smtp, tcp, udp, ….

TCP/IP参考模型:

本章目的:

小结

  • 网络编程中有两个主要的问题
    • 如何准确的定位网络上的一台或多台主机
    • 找到主机之后如何进行通信
  • 网络编程中的要素
    • IPportip
    • 网络通信协议:udp, tcp
  • 万物皆对象

IP

ip地址:InetAddress

用处

  • 唯一定位一台网络上计算机
  • 127.0.0.1(localhost): 本机
  • ip地址的分类
    • IP地址分类:IPV4/IPV6
      • IPV4: 如127.0.0.1。4个字节(32位)组成(0-255),全球42亿个(30亿都在北美,亚洲4亿,2011年就用尽了)
      • IPV6: 如 2001:0bb2:aaaa:0015:0000:00000:1aaa:1312。16字节(128位)组成,8个 无符号整数(4个字节),用的是16进制(16进制占4位)。
    • 公网(互联网使用)和私网(局域网使用)
      • 192.168.xx.xx:局域网,专门给组织内部使用
      • ABCD类地址
    • 域名:记忆 IP 问题
      • IP: www.vip.com

端口

端口表示计算机上的一个程序的进程(类似于:一栋楼代表一个 ip,门牌号代表 端口)

  • 不同的进程有不同的端口号,用来区分软件

  • 被规定:0~65535

  • TCP/UDP端口: 65535 * 2,单个协议下端口号不能冲突,不同协议下,端口可以冲突

  • 端口分类

    • 公有端口:(0~1023)最好不要用

      • HTTP: 80
      • HTTPS:43
      • FTP:21
      • SSH:22
      • Telent: 23
    • 程序注册端口:1024~49151,分配给用户或者程序,建议不要用

      • Tomcat: 8080
      • Mysql:3306
      • Oracle: 1521
    • 动态、私有:49152~65535,建议不要用

      • Idea:63342

      • 查看所有接口

        1
        2
        3
        netstat -ano # 查看所有端口
        netstat -ano|findstr "5900"# 管道流: |,查看指定的端口
        tasklist|findstr "8696" # 查看指定端口的进程

        打开任务管理器: ctrl+shift+esc

    • 代码

      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
      package com.kuangstudy.net.module4;

      import java.net.InetSocketAddress;

      /**
      * @author Qeuroal
      * @date 2021-03-21 16:15
      * @description
      * @since
      */
      public class TestInetSocketAddress {
      public static void main(String[] args) {

      InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 8080);
      System.out.println(inetSocketAddress);
      InetSocketAddress inetSocketAddress2 = new InetSocketAddress("localhost", 8080);
      System.out.println(inetSocketAddress2);

      System.out.println(inetSocketAddress.getAddress());
      // 地址,可以更改hosts文件来更改映射
      System.out.println(inetSocketAddress.getHostName());
      // 端口
      System.out.println(inetSocketAddress.getPort());
      }
      }
    • 图片

通信协议

  • 协议: 约定,就好比我们现在说的普通话
  • 网络通信协议:针对于网络所产生的协议,如:速率,传输码率,代码结构,传输控制……
  • 问题:非常的复杂
  • 大事化小:分层
  • TCP/IP协议簇:实际上是一组协议,不止两个协议。

重要的协议:

  • TCP: 用户传输协议,类似于打电话
  • UDP: 用户数据报协议,类似于发短信

出名的协议:

  • TCP: 用户传输协议
  • IP:网络互连协议

TCP, UDP对比

  • TCP: 打电话

    • 连接:稳定

    • 连接:三次握手四次挥手

      • 三次握手:

        最少需要三次,保证稳定连接!

        A:你瞅啥?

        B:瞅你咋地?

        A:干一场!

      • 四次挥手

        A:我要走了!

        B:你真的要走了吗!

        B:你真的真的要走了吗?

        A:我真的要走了!

    • 客户端、服务端连接

    • 传输完成,释放连接,效率低

  • UDP: 发短信

    • 不连接:不稳定
    • 客户端、服务端连接:没有明确的界限
    • 不管有没有准备好,都可以发给你
    • 类似于导弹攻击
    • DDOS: 洪水攻击(饱和攻击)

TCP

客户端

  1. 连接服务器 socket
  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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.kuangstudy.net.module6;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

/**
* @author Qeuroal
* @date 2021-03-21 16:53
* @description 客户端
* @since
*/
public class TestTcpClient {
public static void main(String[] args) {
Socket socket = null;
OutputStream os = null;
try {
// 1. 要知道服务器的地址
InetAddress serverIP = InetAddress.getByName("127.0.0.1");
// 2. 端口号
int port = 9999;
// 3. 创建一个socket连接
socket = new Socket(serverIP, port);
// 4. 发送消息: io流
os = socket.getOutputStream();
os.write("你好,欢迎学习网络编程".getBytes());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}

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

服务器

  1. 建立服务的端口 ServerSocket
  2. 等待用户的连接 accept
  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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package com.kuangstudy.net.module6;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
* @author Qeuroal
* @date 2021-03-21 16:53
* @description 服务端
* @since
*/
public class TestTcpSever {
public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket socket = null;
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
// 1. 我得有一个地址
serverSocket = new ServerSocket(9999);
while (true) {
// 2. 等待客户端连接过来
socket = serverSocket.accept();
// 3. 读取客户端的消息
is = socket.getInputStream();

// 管道流
baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
System.out.println(baos.toString());
}

} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
if (baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}

if (serverSocket != null) {
try {
serverSocket.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
package com.kuangstudy.net.module7;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
* @author Qeuroal
* @date 2021-03-22 16:13
* @description
* @since
*/
public class TestTcpFileServer {
public static void main(String[] args) throws Exception {
// 1. 创建服务
ServerSocket serverSocket = new ServerSocket(9000);
// 2. 监听客户端的连接
Socket socket = serverSocket.accept();// 阻塞式监听,会一直等待客户端连接
// 3. 获取输入流
InputStream is = socket.getInputStream();
// 4. 文件输出
FileOutputStream fos = new FileOutputStream(new File("receive.png"));
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);

}
// 5. 通知客户端接收完毕
OutputStream os = socket.getOutputStream();
os.write("我接收完毕了,你可以断开了".getBytes());
// 6. 关闭资源
fos.close();
is.close();
socket.close();
serverSocket.close();
}
}

客户端

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
package com.kuangstudy.net.module7;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

/**
* @author Qeuroal
* @date 2021-03-22 16:07
* @description
* @since
*/
public class TestTcpFileClient {
public static void main(String[] args) throws Exception {
// 1. 创建一个socket连接
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000);
// 2. 创建一个输出流
OutputStream os = socket.getOutputStream();
// 3. 读取文件
FileInputStream fis = new FileInputStream(new File("src/resource/xly2.png"));
// 4. 写出文件
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
// 5. 通知服务器,我已经结束了
socket.shutdownOutput(); // 我已经传输完了
// 5. 确定服务器接收完毕,才能够断开连接
InputStream is = socket.getInputStream();
// String byte[]
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer2 = new byte[1024];
int len2;
while ((len2 = is.read(buffer2)) != -1) {
baos.write(buffer2, 0, len2);
}
System.out.println(baos.toString());

// 5. 关闭资源
baos.close();
is.close();
fis.close();
os.close();
socket.close();
}
}

Tomcat

服务端

  • 自定义 S
  • Tomcat服务器 S: Java后台开发!

客户端

  • 自定义 S
  • 浏览器 B

UDP

发短信:不用连接,需要知道对方的地址


涉及到两个类:

  • DatagramPacket
  • DatagramSocket

发送端

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
package com.kuangstudy.net.module9;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
* @author Qeuroal
* @date 2021-03-22 17:29
* @description 不需要连接服务器
* @since
*/
public class TestUdpClient {
public static void main(String[] args) throws Exception {
// 1. 建立一个Socket
DatagramSocket socket = new DatagramSocket(); // 用来发东西的
// 2. 建个包
String msg = "你好啊,服务器!";
// 3. 发送给谁
InetAddress localhost = InetAddress.getByName("localhost");
int port = 9090;
// 数据,数据的长度起始,要发送给谁
DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port);
// 4. 发送包
socket.send(packet);

// 5. 关闭
socket.close();
}
}

接收端

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
package com.kuangstudy.net.module9;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
* @author Qeuroal
* @date 2021-03-22 17:35
* @description 还是要等待客户端的连接
* @since
*/
public class TestUdpServer {
public static void main(String[] args) throws Exception {
// 开放端口
DatagramSocket socket = new DatagramSocket(9090);
// 接收数据包
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length); // 接收
socket.receive(packet); // 阻塞接收
System.out.println(packet.getAddress().getHostName());
System.out.println(new String(packet.getData(), 0, packet.getLength()));

// 关闭连接
socket.close();

}
}

本质上没有服务器:因为可以互相发送,因此就没有服务器的概念

咨询

类似于:广告的客服

xxx: 你好

xxx: 你好

  • BufferedReader : 包装流包装 System.in,为了控制台读取

    1
    new BufferedReader(new InputStreamReader(System.in))

循环发送消息

1

循环接收消息

1

在线咨询

两个人都是发送方,同时也都是接收方

TalkSend

1

TalkReceive

1

TalkStudent

1

TalkTeacher

1

URL

如:https://www.baidu.com/

统一资源定位符:定位资源的,定位互联网上的某一个资源

DNS域名解析: 将 www.baidu.com ==> xxx.xx.xx.xx

组成(可以少,但不能多)

1
协议://ip地址:端口号/项目名/资源
  • URL() : 网络类,代表一个地址
    • param: String
    • url.getProtocol: 得到协议名
    • url.getHost(): 得到主机ip
    • url.getPort(): 得到端口
    • url.getPath(): 文件地址
    • url.getFile(): 得到文件全路径
    • url.getQuery: 得到参数(如:查询的名字)
    • url.openConnection(): 打开连接
    • urlConnection.getInputStream(): 得到流
    • urlConnection.disconnect(): 断开连接

下载文件

  1. 下载地址
  2. 连接到这个资源,用 HTTP 连接
  3. 下载

getResource

getResource读取的是 out 下的文件,即 classpath

  • 相对路径: 即在当前包内的路径,如: Test.class.getResource("xly2.png");, xly2.png在当前包内,或者说和运行的class在同一目录下
  • 绝对路径: 用 / 表示,代表是当前项目下,如 Test.class.getResource("/resource/xly2.png"),如上图可见 resource 的位置

new File

读取的是 目录文件,如下所示

1
new FileInputStream(new File("src/resource/xly2.png"));