此博客是我看 B站 韩顺平 老师 的课程做的笔记

InetAddress类(获取IP地址)

使用代码

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
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
* @author 张永锐
*/
public class API_ {
public static void main(String[] args) throws UnknownHostException {
//获取本机的InetAddress对象
InetAddress localHost = InetAddress.getLocalHost();
System.out.println("localHost = " + localHost);//Zhangyr/192.168.57.1

//根据指定主机名 获取 InetAddress 对象
InetAddress host1 = InetAddress.getByName("Zhangyr");
System.out.println("host1 = " + host1);

//根据域名返回 InetAddress 对象,比www.baidu.com
InetAddress host2 = InetAddress.getByName("www.baidu.com");//!不联网就要报错
System.out.println("host2 = " + host2);//host2 = www.baidu.com/14.215.177.38

//通过 InetAddress 对象,获取对应的地址
String hostAddress = host1.getHostAddress();
System.out.println("host1 对应的IP = " + hostAddress);//host1 对应的IP = 192.168.57.1

//通过 InetAddress 对象,获取对应的主机名/域名
String hostName = host2.getHostName();
System.out.println("host2 对应的主机名/域名 = " + hostName);//host2 对应的主机名/域名 = www.baidu.com
}
}

Socket类(实现网络编程)

基本介绍

  1. 套接字(Sock)开发网络引用程序被广泛采用,以至于称为事实上的标准
  2. 通信的两端都要右Socket,是两台机器间通信的端口
  3. 网络通信其实就是Socket间通信
  4. Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输
  5. 一般主动发起通信的应用程序属客户端,等待通信请求的为服务端

通讯时读写数据:
socket.getOutputStream()
socket.getInputStream()

TCP编程和UDP编程

网络编程一般有TCP编程(稳定,可靠,速度慢)和UDP编程(不稳定、不可靠、速度快)两种

TCP网络通信编程

  1. 基于客户端——服务端的网络通信
  2. 底层使用的是TCP/IP协议
  3. 应用场景举例:客户端发送数据,服务端接收并显示

一定要关闭socket,否者后面可能会导致连接不上

TCP字节流编程

ServerSocket类:

此类实现服务器套接字。服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果。
服务器套接字的实际工作由 SocketImpl 类的实例执行。应用程序可以更改创建套接字实现的套接字工厂来配置它自身,从而创建适合本地防火墙的套接字。
ServerSocket与Socket的不同,ServerSocket的每一个accept()都可连接到一个方法,可以连接很多Socket也是多并发的一个体现

Socket类:

此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。
套接字的实际工作由 SocketImpl 类的实例执行。应用程序通过更改创建套接字实现的套接字工厂可以配置它自身,以创建适合本地防火墙的套接字。
编程练习1

  1. 编写一个服务器端和一个客户端
  2. 服务器端在 9999 端口监听
  3. 客户端连接到服务器端,发送“hello,server”,然后退出
  4. 服务器端接收到 客户端发送的消息,输出,并退出
代码展示

肯定要有两个程序

服务端程序

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
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
* todo 服务端
* @author 张永锐
*/
public class SocketTCP01Server {
public static void main(String[] args) throws IOException {
// todo 在本机的9999端口监听,等待连接
//? ServerSocket(int port) 创建绑定到特定端口的服务器套接字。
//! 要求本机没有其他程序或者服务在监听9999
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端9999正在等待连接...");

// todo 没有客户端连接程序时,程序会堵塞,等待连接
//? 如果有客户端连接,则会返回 Socket 对象,程序继续
Socket socket = serverSocket.accept();
System.out.println("服务端成功连接");

// todo 读取客户端数据
//? 得到一个于socket相关的输入流
InputStream iis = socket.getInputStream();
//? 读入数据
int data_read = 0;
byte[] buf = new byte[1024];
while((data_read = iis.read(buf)) != -1){
System.out.println(new String(buf,0,data_read));
}

// todo 关闭流和socket
iis.close();
socket.close();
System.out.println("服务端退出...");
}
}

客户端程序

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
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

/**
* todo 客户端
* @author 张永锐
*/
public class SocketTCP01Client {
public static void main(String[] args) throws IOException {
// todo 连接服务器
//? Socket(InetAddress address, int port) 创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
//? 连接 9999 端口 如果连接成功 返回一个Socket对象
Socket socket = new Socket(InetAddress.getLocalHost(),9999);
System.out.println("客户端 socket 返回 = " + socket.getClass());

// todo 发送Hello,Server 到服务端
//? 得到一个和socket想关联的输出流,一定时要和socket相关联的输出流
OutputStream sos = socket.getOutputStream();
//? 通过得到的输出流 ,将要写的话写到数据通道
sos.write("Hello,server".getBytes());

// todo 关闭流对象和socket,必须关闭!!!
sos.close();
socket.close();
System.out.println("客户端退出...");
}
}
说明

因为是在同一台电脑上操作,所以客户端的IP地址是InetAddress.getLocalHost()也就是本地地址,如果要与别的电脑连接,就传入”xxx.xxx.xxx.xxx”

编程练习2

用字节流

  1. 编写一个服务端和一个客户端
  2. 服务端在9999端口监听
  3. 客户端连接到服务器端,发送”Hello,Server”,并接收服务器端回发的”Hello,Client”,再退出
  4. 服务器端接收到客户端发送的信息,输出,再发送”Hello,Client”,再退出

这道题的重点是发送完消息和接收完消息后都应该要有一个结束标记,即socket.shutdownOutput();socket.shutdownInput()
注意: 流要最后一起关闭,不是用完就关闭,否则会造成线程问题

代码展示

服务端代码

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
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
* @author 张永锐
*/
@SuppressWarnings({"all"})
public class SocketTCP02Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端等待连接");

Socket socket = serverSocket.accept();
System.out.println("服务端已连接");

// todo 接收数据
InputStream inputStream = socket.getInputStream();
int read_length = 0;
byte[] buf = new byte[1024];
while((read_length = inputStream.read(buf)) != -1){
System.out.println(new String(buf,0,read_length));
}
socket.shutdownInput();

// todo 获取socket相关联的OutputStream()
OutputStream outputStream = socket.getOutputStream();
outputStream.write("Hello,Client".getBytes());
socket.shutdownOutput();

//!最后一起把流关掉
inputStream.close();
outputStream.close();
socket.close();
System.out.println("服务端退出");
}
}

客户端代码

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
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

/**
* @author 张永锐
*/
@SuppressWarnings({"all"})
public class SocketTCP02Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);

// todo 发送消息
OutputStream outputStream = socket.getOutputStream();
outputStream.write("Hello,Server".getBytes());

socket.shutdownOutput();

// todo 接收消息
InputStream inputStream = socket.getInputStream();
int read_length = 0;
byte[] buf = new byte[1024];
while((read_length = inputStream.read(buf)) != -1){
System.out.println(new String(buf,0,read_length));
}
socket.shutdownInput();

//!最后一起把流关掉
outputStream.close();
inputStream.close();
socket.close();
System.out.println("客户端退出...");
}
}
编程练习3

实际上就是第二个题,但是要求用字符流

  1. 编写一个服务端和一个客户端
  2. 服务端在9999端口监听
  3. 客户端连接到服务端,发送”Hello,Server”,并接收服务端回发的”Hello,Client”,再退出
  4. 服务端接收接收到客户端发送的信息,输出,再发送”Hello,Client”,再退出

需要使用转换流,即OutputStream->Writer;InputStream->Reader。并且,可以使用Writer.newLine()来作为结束标记,但是,需要使用readLine()来读取[这就相当于是一种协议了]

代码展示

服务端代码

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
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
* @author 张永锐
*/
@SuppressWarnings({"all"})
public class SocketTCP03Server {
public static void main(String[] args) throws IOException {
// todo 连接
ServerSocket serverSocket = new ServerSocket(9999);
Socket socket = serverSocket.accept();

// todo 接收数据
InputStream inputStream = socket.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String s = bufferedReader.readLine();
System.out.println(s);

// todo 输出数据
OutputStream outputStream = socket.getOutputStream();
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
bufferedWriter.write("Hello,Client");
bufferedWriter.newLine();
bufferedWriter.flush();//!一定要刷新,否则读不进去

//!关流
bufferedWriter.close();
bufferedReader.close();
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
28
29
30
31
32
33
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

/**
* @author 张永锐
*/
@SuppressWarnings({"all"})
public class SocketTCP03Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);

// todo 输出数据
OutputStream outputStream = socket.getOutputStream();
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
bufferedWriter.write("Hello,Server");
bufferedWriter.newLine();
bufferedWriter.flush();//!一定要刷新,否则读不进去

// todo 接收数据
InputStream inputStream = socket.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String s = bufferedReader.readLine();
System.out.println(s);

//!关流
bufferedWriter.close();
bufferedReader.close();
socket.close();
}
}

TCP文件编程

编程练习1
  1. 编写一个服务端和一个客户端
  2. 服务端在9999端口监听
  3. 客户端连接到服务端,发送一张图片,之后退出
  4. 服务器端接收到客户端发送的图片,保存到e盘下
  5. 该程序需要使用StreamUtils.java;BufferedInputStreamBufferedOutputStream
代码展示

服务端代码

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
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
* @author 张永锐
*/
public class TCPFileUploadServer {
public static void main(String[] args) throws Exception {
// todo 服务端再本地监听9999
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端在9999端口监听...");
// todo 等待连接
Socket socket = serverSocket.accept();
System.out.println("等待连接...");

// todo 读取客户端发送的数据
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
// todo 读取bis,拿到一个字节数组
byte[] bytes = StreamUtils.streamToByteArray(bis);
// todo 得到 bytes 数组,存入文件
String filePath = "src\\鹅国小酒馆3.mp4";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
bos.write(bytes);

//!关闭流
bos.close();
bis.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
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

/**
* @author 张永锐
*/
public class TCPFileUploadClient {
public static void main(String[] args) throws Exception {
// todo 客户端连接服务端
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
// todo 创建读取文件的的输入流
String filePath = "e:\\鹅国小酒馆.mp4";
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
// todo 把文件读到字节数组中
byte[] bytes = StreamUtils.streamToByteArray(bis);//bytes就是filePath对应的字节数组
// todo 通过socket获取输出流,将bytes数据发给服务端
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(bytes);//将文件对应的字节数组发送出去
bis.close();
socket.shutdownOutput();//结束标记

bos.close();
socket.close();
}
}
编程练习2

是编程练习1的进阶

  1. 编写一个服务端和一个客户端
  2. 服务端在9999端口监听
  3. 客户端连接到服务端,发送一张图片
  4. 服务器端接收到客户端发送的图片,保存到e盘,发送”收到图片”再退出
  5. 客户端接收到服务器端发送的”收到图片”后再退出
  6. 该程序需要使用StreamUtils.java;BufferedInputStreamBufferedOutputStream
代码展示

服务端代码

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
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
* @author 张永锐
*/
public class TCPFileUploadServer {
public static void main(String[] args) throws Exception {
// todo 服务端再本地监听9999
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端在9999端口监听...");
// todo 等待连接
Socket socket = serverSocket.accept();
System.out.println("等待连接...");

// todo 读取客户端发送的数据
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
// todo 读取bis,拿到一个字节数组
byte[] bytes = StreamUtils.streamToByteArray(bis);
// todo 得到 bytes 数组,存入文件
String filePath = "e:\\鹅国小酒馆3.mp4";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
bos.write(bytes);
bos.close();

// todo 向客户端回复"收到文件"
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("收到图片");
bw.flush();//!刷新换行符
socket.shutdownOutput();//结束标记

//!关闭流
bw.close();
bis.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
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

/**
* @author 张永锐
*/
public class TCPFileUploadClient {
public static void main(String[] args) throws Exception {
// todo 客户端连接服务端
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
// todo 创建读取文件的的输入流
String filePath = "e:\\鹅国小酒馆.mp4";
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
// todo 把文件读到字节数组中
byte[] bytes = StreamUtils.streamToByteArray(bis);//bytes就是filePath对应的字节数组
// todo 通过socket获取输出流,将bytes数据发给服务端
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(bytes);//将文件对应的字节数组发送出去
bis.close();
socket.shutdownOutput();//结束标记

// todo 接收服务端消息
InputStream inputStream = socket.getInputStream();
String s = StreamUtils.streamToString(inputStream);
System.out.println(s);

//!关闭流
inputStream.close();
bos.close();
socket.close();
}
}

netstat指令

  1. netstat -an可以查看当前主机网络情况,包括端口监听情况网络连接情况
  2. netstat -an|more 可以分页显示
  3. netstat -anb|more 可以分页显示并且可以显示使用的程序
  4. 要求在dos控制台下执行

其中本地地址冒号后面的数字代表端口(一般都是服务端),外部地址一般是客户端的IP地址(127.0.0.1还是表示本地地址),状态表示是否是在监听
运行服务端程序。

TCP连接秘密

当连接上后,客户端也会有一个端口(这个端口是随机的),假设使用客户端与服务端连接后,上图中能找到一个外部地址与本地地址为0.0.0.0:9999连接的地址,后面的冒号代表地址,并且状态为ESTABLISHED

UDP网络编程

基本介绍

  1. DatagramSocketDatagramPacket[数据包/数据报] 实现了基于UDP协议网络程序
  2. UDP数据报通过数据报套接字 DatagramSocket发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以送达
  3. DatagramPacket对象封装了UDP数据报,在数据报中包含了发送端口的IP地址和的端口号以及接收端口的IP地址和端口号
  4. UDP协议中每个数据报都给出了完整的地址信息,因此无需建立发送方和接收方的连接

编程练习

  1. 编写一个接收端A,和一个发送端B
  2. 接收端A在9999端口等待接收数据
  3. 发送端B向接收端A发送数据,发送”Hello,明天吃火锅”
  4. 接收端A接收到发送端B的数据后,回复”好的,明天见”,退出
  5. 发送端B接收到数据后再退出