JAVA Foundation-Chapter 20 Network Programming

main content

Software architecture CS/BS
network communication three elements
TCP communication
Socket socket
ServerSocket

teaching objectives

Able to distinguish the characteristics of UDP and TCP protocols.
Able to name two commonly used classes under the TCP protocol.
Able to write string data transmission programs
under the TCP protocol.
Able to understand the file upload case under the TCP protocol. Able to understand the case 2 under the TCP protocol.

Chapter 1 Introduction to Network Programming

1.1 Software structure

C/S结构 :全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、迅雷等软件。

B/S structure: The full name is Browser/Server structure, which refers to the browser and server structure. Common browsers include Google, Firefox, etc.

Both architectures have their own advantages, but no matter which architecture, they are inseparable from the support of the network. Network programming is a program that realizes communication between two computers under a certain protocol.

1.2 Network communication protocol

Network communication protocol: The communication protocol is the rules that computers must comply with. Only by complying with these rules can computers communicate. This is like a car driving on the road must comply with traffic rules. The agreement has unified regulations on the data transmission format, transmission rate, and transmission steps. The two parties must comply with it at the same time to complete the data exchange.

TCP/IP协议: 传输控制协议/因特网互联协议( Transmission Control Protocol/Internet Protocol),是
Internet最基本、最广泛的协议。它定义了计算机如何连入因特网,以及数据如何在它们之间传输的标准。它
的内部包含一系列的用于处理数据通信的协议,并采用了 4 层的分层模型,每一层都呼叫它的下一层所提供的
协议来完成自己的需求。

1.3 Protocol classification

The communication protocol is quite complicated. The classes and interfaces contained in the java.net package provide low-level communication details. We can directly use
these classes and interfaces to focus on network program development without considering the details of communication.

java.net 包中提供了两种常见的网络协议的支持:
TCP:传输控制协议 (Transmission Control Protocol)。TCP协议是面向连接的通信协议,即传输数据之前,
在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。
三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可
靠。
第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。
第三次握手,客户端再次向服务器端发送确认信息,确认连接。整个交互过程如下图所示。
After the three-way handshake is completed and the connection is established, the client and server can start data transmission. Due to this connection-oriented feature, the TCP protocol can
In order to ensure the safety of the transmitted data, it is widely used, such as downloading files and browsing web pages.
UDP:用户数据报协议(User Datagram Protocol)。UDP协议是一个面向无连接的协议。传输数据时,不需
要建立连接,不管对方端服务是否启动,直接将数据、数据源和目的地都封装在数据包中,直接发送。每个
数据包的大小限制在64k以内。它是不可靠协议,因为无连接,所以传输速度快,但是容易丢失数据。日常应
用中,例如视频会议、QQ聊天等。

1.4 Three Elements of Network Programming

protocol

Protocol: The rules that must be followed in computer network communication have already been introduced and will not be repeated.

IP address

IP地址:指互联网协议地址(Internet Protocol Address),俗称IP。IP地址用来给一个网络中的计算机设
备做唯一的编号。假如我们把“个人电脑”比作“一台电话”的话,那么“IP地址”就相当于“电话号码”。

IP address classification

IPv4:是一个 32 位的二进制数,通常被分为 4 个字节,表示成a.b.c.d 的形式,例如192.168.65.100 。其
中a、b、c、d都是0~255之间的十进制整数,那么最多可以表示 42 亿个。
IPv6:由于互联网的蓬勃发展,IP地址的需求量愈来愈大,但是网络地址资源有限,使得IP的分配越发紧张。
有资料显示,全球IPv4地址在 2011 年 2 月分配完毕。
为了扩大地址空间,拟通过IPv6重新定义地址空间,采用 128 位地址长度,每 16 个字节一组,分成 8 组十六进
制数,表示成ABCD:EF01:2345:6789:ABCD:EF01:2345:6789,号称可以为全世界的每一粒沙子编上一个网
址,这样就解决了网络地址资源数量不够的问题。

Common commands

Check the IP address of the machine, enter in the console:
To check whether the network is connected, type in the console:
Special IP address
本机IP地址:127.0.0.1、localhost 。

The port number

Network communication is essentially a communication between two processes (applications). Each computer has many processes, so how to distinguish between network communication
What about these processes?
If the IP address can uniquely identify the device in the network, then the port number can uniquely identify the process (application) in the device.
Port number: an integer represented by two bytes, and its value range is 0 65535. Among them, the port number between 0 and 1023 is used in some well-known networks
Network services and applications, ordinary applications need to use port numbers above 1024. If the port number is occupied by another service or application, it will
Cause the current program to fail to start.
Using the triple combination of protocol + IP address + port number, you can identify the process in the network, then the communication between processes can use this identification and
It processes interactively.

Chapter 2 TCP Communication Program

2.1 Overview

TCP communication can realize data exchange between two computers. The two ends of the communication must be strictly divided into the client and the server.

Steps when both ends communicate:

1. 服务端程序,需要事先启动,等待客户端的连接。
2. 客户端主动连接服务器端,连接成功才能通信。服务端不可以主动连接客户端。

In Java, two classes are provided to implement TCP communication programs:

1. 客户端:java.net.Socket 类表示。创建Socket对象,向服务端发出连接请求,服务端响应请求,两者建
立连接开始通信。
2. 服务端:java.net.ServerSocket 类表示。创建ServerSocket对象,相当于开启一个服务,并等待客户端
的连接。

2.2 Socket class

Socket 类:该类实现客户端套接字,套接字指的是两台设备之间通讯的端点。

Construction method

ipconfig
ping 空格 IP地址
ping 220.181.57.
public Socket(String host, int port) :创建套接字对象并将其连接到指定主机上的指定端口号。如果指
定的host是null ,则相当于指定地址为回送地址。
小贴士:回送地址(127.x.x.x) 是本机回送地址(Loopback Address),主要用于网络软件测试以及本
地机进程间通信,无论什么程序,一旦使用回送地址发送数据,立即返回,不进行任何网络传输。

For example, the code is as follows:

Member method

public InputStream getInputStream() : 返回此套接字的输入流。
如果此Scoket具有相关联的通道,则生成的InputStream 的所有操作也关联该通道。
关闭生成的InputStream也将关闭相关的Socket。
public OutputStream getOutputStream() : 返回此套接字的输出流。
如果此Scoket具有相关联的通道,则生成的OutputStream 的所有操作也关联该通道。
关闭生成的OutputStream也将关闭相关的Socket。
public void close() :关闭此套接字。
一旦一个socket被关闭,它不可再使用。
关闭此socket也将关闭相关的InputStream和OutputStream 。
public void shutdownOutput() : 禁用此套接字的输出流。
任何先前写出的数据将被发送,随后终止输出流。

2.3 ServerSocket class

ServerSocket类:这个类实现了服务器套接字,该对象等待通过网络的请求。

Construction method

public ServerSocket(int port) :使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指
定的端口号上,参数port就是端口号。

For example, the code is as follows:

Member method

public Socket accept() :侦听并接受连接,返回一个新的Socket对象,用于和客户端实现通信。该方法
会一直阻塞直到建立连接。

2.4 Simple TCP network program

TCP communication analysis diagram

1. 【服务端】启动,创建ServerSocket对象,等待连接。
Socket client = new Socket("127.0.0.1",  6666 );
ServerSocket server = new ServerSocket( 6666 );
2. 【客户端】启动,创建Socket对象,请求连接。
3. 【服务端】接收连接,调用accept方法,并返回一个Socket对象。
4. 【客户端】Socket对象,获取OutputStream,向服务端写出数据。
5. 【服务端】Scoket对象,获取InputStream,读取客户端发送的数据。
到此,客户端向服务端发送数据成功。
Since then, the server writes data back to the client.
6. 【服务端】Socket对象,获取OutputStream,向客户端回写数据。
7. 【客户端】Scoket对象,获取InputStream,解析回写数据。
8. 【客户端】释放资源,断开连接。

The client sends data to the server

Server-side implementation:
public^ class^ ServerTCP {
public static void main(String[] args) throws IOException {
System.out.println("服务端启动 , 等待连接 .... ");
// 1.创建 ServerSocket对象,绑定端口,开始等待连接
ServerSocket ss = new ServerSocket( 6666 );
// 2.接收连接 accept 方法, 返回 socket 对象.
Socket server = ss.accept();
// 3.通过socket 获取输入流
InputStream is = server.getInputStream();
// 4.一次性读取数据
// 4.1 创建字节数组
byte[] b = new byte[ 1024 ];
// 4.2 据读取到字节数组中.
int len = is.read(b);
// 4.3 解析数组,打印字符串信息
String msg = new String(b,  0 , len);
System.out.println(msg);
//5.关闭资源.
is.close();
server.close();
    }
}
Client implementation:

The server writes data back to the client

Server-side implementation:
Client implementation:
public class ClientTCP {
public static void main(String[] args) throws Exception {
System.out.println("客户端 发送数据");
// 1.创建 Socket ( ip , port ) , 确定连接到哪里.
Socket client = new Socket("localhost",  6666 );
// 2.获取流对象 . 输出流
OutputStream os = client.getOutputStream();
// 3.写出数据.
os.write("你好么? tcp ,我来了".getBytes());
// 4. 关闭资源 .
os.close();
client.close();
}
}
public class ServerTCP {
public static void main(String[] args) throws IOException {
System.out.println("服务端启动 , 等待连接 .... ");
// 1.创建 ServerSocket对象,绑定端口,开始等待连接
ServerSocket ss = new ServerSocket( 6666 );
// 2.接收连接 accept 方法, 返回 socket 对象.
Socket server = ss.accept();
// 3.通过socket 获取输入流
InputStream is = server.getInputStream();
// 4.一次性读取数据
// 4.1 创建字节数组
byte[] b = new byte[ 1024 ];
// 4.2 据读取到字节数组中.
int len = is.read(b);
// 4.3 解析数组,打印字符串信息
String msg = new String(b,  0 , len);
System.out.println(msg);
// =================回写数据=======================
// 5. 通过 socket 获取输出流
OutputStream out = server.getOutputStream();
// 6. 回写数据
out.write("我很好,谢谢你".getBytes());
// 7.关闭资源.
out.close();
is.close();
server.close();
    }
}

Chapter 3 Comprehensive Case

3.1 File upload case

File upload analysis diagram

1. [Client] Input stream, read file data from hard disk to program.
2. [Client] Output stream, write file data to server.
3. [Server] Input stream, read file data to server program.
4. [Server] Output stream, write file data to server hard disk.

Basic realization

public class ClientTCP {
public static void main(String[] args) throws Exception {
System.out.println("客户端 发送数据");
// 1.创建 Socket ( ip , port ) , 确定连接到哪里.
Socket client = new Socket("localhost",  6666 );
// 2.通过Scoket,获取输出流对象
OutputStream os = client.getOutputStream();
// 3.写出数据.
os.write("你好么? tcp ,我来了".getBytes());
// ==============解析回写=========================
// 4. 通过Scoket,获取 输入流对象
InputStream in = client.getInputStream();
// 5. 读取数据数据
byte[] b = new byte[ 100 ];
int len = in.read(b);
System.out.println(new String(b,  0 , len));
// 6. 关闭资源 .
in.close();
os.close();
client.close();
}
}
Server-side implementation:
Client implementation:
public class FileUpload_Server {
public static void main(String[] args) throws IOException {
System.out.println("服务器 启动.....  ");
// 1. 创建服务端ServerSocket
ServerSocket serverSocket = new ServerSocket( 6666 );
// 2. 建立连接
Socket accept = serverSocket.accept();
// 3. 创建流对象
// 3.1 获取输入流,读取文件数据
BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
// 3.2 创建输出流,保存到本地 .
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.jpg"));
// 4. 读写数据
byte[] b = new byte[ 1024  *  8 ];
int len;
while ((len = bis.read(b)) != ‐ 1 ) {
bos.write(b,  0 , len);
        }
//5. 关闭 资源
bos.close();
bis.close();
accept.close();
System.out.println("文件上传已保存");
    }
}
public class FileUPload_Client {
public static void main(String[] args) throws IOException {
// 1.创建流对象
// 1.1 创建输入流,读取本地文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("test.jpg"));
// 1.2 创建输出流,写到服务端
Socket socket = new Socket("localhost",  6666 );
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
//2.写出数据.
byte[] b = new byte[ 1024  *  8  ];
int len ;
while (( len = bis.read(b))!=‐ 1 ) {
bos.write(b,  0 , len);
bos.flush();
        }
System.out.println("文件发送完毕");
// 3.释放资源
bos.close();
socket.close();
bis.close();

File upload optimization analysis

1. The file name is hard to write
On the server side, if the name of the saved file is hard-coded, it will eventually lead to the server hard disk and only one file will be retained. It is recommended to use the system time optimization
To ensure that the file name is unique, the code is as follows:
2. The problem of circular reception
On the server side, it means that after saving a file, it is closed, and subsequent users can no longer upload it. This is not in line with the reality. The use of cyclic improvement can continue
To receive files from different users, the code is as follows:
3. Efficiency issues
On the server side, when receiving large files, it may take a few seconds. At this time, it cannot receive uploads from other users. Therefore, it is better to use multi-threading technology.
The code is as follows:

Optimized implementation

System.out.println("文件上传完毕 ");
}
}
FileOutputStream fis = new FileOutputStream(System.currentTimeMillis()+".jpg") // 文件名称
BufferedOutputStream bos = new BufferedOutputStream(fis);
// 每次接收新的连接,创建一个Socket
while(true){
Socket accept = serverSocket.accept();
    ......
}
while(true){
Socket accept = serverSocket.accept();
// accept 交给子线程处理.
new Thread(() ‐> {
......
InputStream bis = accept.getInputStream();
......
    }).start();
}
public class FileUpload_Server {
public static void main(String[] args) throws IOException {
System.out.println("服务器 启动.....  ");
// 1. 创建服务端ServerSocket
ServerSocket serverSocket = new ServerSocket( 6666 );
// 2. 循环接收,建立连接
while (true) {
Socket accept = serverSocket.accept();
/*
  1. The socket object is handed over to the child thread for processing, read and write operations

Information write-back analysis diagram

The first four steps are consistent with the basic file upload.
5. [Server] Obtain the output stream and write back data.
6. [Client] Obtain the input stream and parse the write-back data.

Write-back implementation

Runnable接口中,只有一个run方法,使用lambda表达式简化格式
*/
new Thread(() ‐> {
try (
//3.1 获取输入流对象
BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
//3.2 创建输出流对象, 保存到本地 .
FileOutputStream fis = new FileOutputStream(System.currentTimeMillis() +
".jpg");
BufferedOutputStream bos = new BufferedOutputStream(fis);) {
// 3.3 读写数据
byte[] b = new byte[ 1024  *  8 ];
int len;
while ((len = bis.read(b)) != ‐ 1 ) {
bos.write(b,  0 , len);
                    }
//4. 关闭 资源
bos.close();
bis.close();
accept.close();
System.out.println("文件上传已保存");
                } catch (IOException e) {
e.printStackTrace();
                }
            }).start();
        }
    }
}
Client implementation:
public class FileUpload_Server {
public static void main(String[] args) throws IOException {
System.out.println("服务器 启动.....  ");
// 1. 创建服务端ServerSocket
ServerSocket serverSocket = new ServerSocket( 6666 );
// 2. 循环接收,建立连接
while (true) {
Socket accept = serverSocket.accept();
/*
  1. The socket object is handed over to the child thread for processing and read and write operations. In the
    Runnable interface, there is only one run method, which uses lambda expressions to simplify the format.
    */
    new Thread(() ‐> { try ( //3.1 Get the input stream object BufferedInputStream bis = new BufferedInputStream(accept.getInputStream()); //3.2 Create an output stream object and save it locally. FileOutputStream fis = new FileOutputStream(System.currentTimeMillis() + “.jpg”); BufferedOutputStream bos = new BufferedOutputStream(fis); ) { // 3.3 Read and write data byte[] b = new byte[ 1024 * 8 ]; int len; while ((len = bis.read(b)) != ‐ 1) { bos.write(b, 0, len) ; }













// 4.=======信息回写===========================
System.out.println("back ........");
OutputStream out = accept.getOutputStream();
out.write("上传成功".getBytes());
out.close();
//================================
//5. 关闭 资源
bos.close();
bis.close();
accept.close();
System.out.println("文件上传已保存");
                } catch (IOException e) {
e.printStackTrace();
                }
            }).start();
        }
    }
}
public class FileUpload_Client {
public static void main(String[] args) throws IOException {

3.2 Simulate B\S server

Simulate the web server, use the browser to access the server program written by yourself, and check the web page effect.

case analysis

1. 准备页面数据,web文件夹。
复制到我们Module中,比如复制到day08中
2. 我们模拟服务器端,ServerSocket类监听端口,使用浏览器访问
// 1. Create a stream object
// 1.1 Create input stream and read local file
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("test.jpg"));
// 1.2 创建输出流,写到服务端
Socket socket = new Socket("localhost",  6666 );
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
//2.写出数据.
byte[] b = new byte[ 1024  *  8  ];
int len ;
while (( len = bis.read(b))!=‐ 1 ) {
bos.write(b,  0 , len);
        }
// 关闭输出流,通知服务端,写出数据完毕
socket.shutdownOutput();
System.out.println("文件发送完毕");
// 3. =====解析回写============
InputStream in = socket.getInputStream();
byte[] back = new byte[ 20 ];
in.read(back);
System.out.println(new String(back));
in.close();
// ============================
// 4.释放资源
socket.close();
bis.close();
    }
}
3. The byte input stream in the server program can read the request information sent by the browser

GET/web/index.html HTTP/1.1 is the request message of the browser. /web/index.html is the server-side resource that the browser wants to request,
and the requested resource is obtained by string cutting.

Case realization

Server-side implementation:
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket( 8000 );
Socket socket = server.accept();
InputStream in = socket.getInputStream();
byte[] bytes = new byte[ 1024 ];
int len = in.read(bytes);
System.out.println(new String(bytes, 0 ,len));
socket.close();
server.close();
}
//Convert the stream, read the first line of the browser request
BufferedReader readWb = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String requst = readWb.readLine();
//取出请求资源的路径
String[] strArr = requst.split(" ");
//去掉web前面的/
String path = strArr[ 1 ].substring( 1 );
System.out.println(path);
public class SerDemo {
public static void main(String[] args) throws IOException {
System.out.println("服务端 启动 , 等待连接 .... ");
// 创建ServerSocket 对象
ServerSocket server = new ServerSocket( 8888 );
Socket socket = server.accept();
// 转换流读取浏览器的请求消息
BufferedReader readWb = new

Visit effect

Firefox
Tips: Different browsers have different kernels, and the parsing effect may be different.
It is found that there are many forks in the browser, indicating that the browser did not read the picture information.
The working principle of the browser is that it will start a thread for separate access when encountering pictures, so thread technology is added on the server side.
BufferedReader(new InputStreamReader(socket.getInputStream()));
String requst = readWb.readLine();
// 取出请求资源的路径
String[] strArr = requst.split(" ");
// 去掉web前面的/
String path = strArr[ 1 ].substring( 1 );
// 读取客户端请求的资源文件
FileInputStream fis = new FileInputStream(path);
byte[] bytes= new byte[ 1024 ];
int len =  0  ;
// 字节输出流,将文件写会客户端
OutputStream out = socket.getOutputStream();
// 写入HTTP协议响应头,固定写法
out.write("HTTP/1.1 200 OK\r\n".getBytes());
out.write("Content‐Type:text/html\r\n".getBytes());
// 必须要写入空行,否则浏览器不解析
out.write("\r\n".getBytes());
while((len = fis.read(bytes))!=‐ 1 ){
out.write(bytes, 0 ,len);
        }
fis.close();
out.close();
readWb.close();
socket.close();
server.close();
    }
}
Visit effect:
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket( 8888 );
while(true){
Socket socket = server.accept();
new Thread(new Web(socket)).start();
        }
    }
static class Web implements Runnable{
private Socket socket;
public Web(Socket socket){
this.socket=socket;
        }
public void run() {
try{
//转换流,读取浏览器请求第一行
BufferedReader readWb = new
BufferedReader(new InputStreamReader(socket.getInputStream()));
String requst = readWb.readLine();
//取出请求资源的路径
String[] strArr = requst.split(" ");
System.out.println(Arrays.toString(strArr));
String path = strArr[ 1 ].substring( 1 );
System.out.println(path);
FileInputStream fis = new FileInputStream(path);
System.out.println(fis);
byte[] bytes= new byte[ 1024 ];
int len =  0  ;
//向浏览器 回写数据
OutputStream out = socket.getOutputStream();
out.write("HTTP/1.1 200 OK\r\n".getBytes());
out.write("Content‐Type:text/html\r\n".getBytes());
out.write("\r\n".getBytes());
while((len = fis.read(bytes))!=‐ 1 ){
out.write(bytes, 0 ,len);
                }
fis.close();
out.close();
readWb.close();
socket.close();
            }catch(Exception ex){
            }
        }
    }
}
Illustration:

Guess you like

Origin blog.csdn.net/weixin_43419256/article/details/108230771