# 第十章 网络编程

# 10.1 网络的相关概念

# 10.2 InetAddress类

相关方法:

# 10.3 Socket

# 10.3.1 Socket基本介绍

(1)Socket(套接字)开发网络应用程序被广泛应用

(2)通信的两端都要有Socket,是两台机器间通信的端点

(3)网络通信其实就是Socket间的通信

(4)Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输

# 10.4 TCP网络通信编程

# 10.4.1 TCP字节流编程1

//客户端
public class SocketTCP01Client {
    public static void main(String[] args) throws IOException {
        //1. 连接服务器(ip,端口)
        //链接本机的9999端口,如果连接成功,返回Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("客户端 socket返回= " + socket.getClass());
        //2. 连接上后,生成Socket,通过socket.getOutputStream()得到和socket对象关联的输出流对象
        OutputStream outputStream = socket.getOutputStream();
        //3. 通过输出流,写入数据到数据通道
        outputStream.write("hello,server".getBytes());
        //4. 关闭流对象和socket,必须关闭
        outputStream.close();
        socket.close();
        System.out.println("客户端退出");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//服务端
public class SocketTCP01Server {
    public static void main(String[] args) throws IOException {
        //1. 在本机的9999端口监听,等待连接
        //   细节: 要求在本机没有其他服务在监听9999
        ServerSocket serverSocket = new ServerSocket(9999);//ServerSocket可以创建多个Socket
        System.out.println("服务端在9999端口监听,等待连接..");
        //2. 当没有客户端连接9999端口时,程序会阻塞,等待连接
        //   如果有客户端连接,则会返回Socket对象,程序继续
        Socket socket = serverSocket.accept();
        System.out.println("服务端 socket = " + socket.getClass());
        //3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据,显示
        InputStream inputStream = socket.getInputStream();
        //4. IO读取
        byte[] buf = new byte[1024];
        int readLen = 0;
        while ((readLen = inputStream.read(buf)) != -1) {
            System.out.println(new String(buf, 0, readLen));
        }
        //5. 关闭流
        inputStream.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

# 10.4.2 TCP字节流编程2

//客户端
public class SocketTCP01Client {
    public static void main(String[] args) throws IOException {
        //1. 连接服务器(ip,端口)
        //链接本机的9999端口,如果连接成功,返回Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("客户端 socket返回= " + socket.getClass());
        //2. 连接上后,生成Socket,通过socket.getOutputStream()得到和socket对象关联的输出流对象
        OutputStream outputStream = socket.getOutputStream();
        //3. 通过输出流,写入数据到数据通道
        outputStream.write("hello,server".getBytes());
        //4. 结束标记
        socket.shutdownOutput();
        //5. 获取和socket关联的输入流,读取数据(字节)并显示
        InputStream inputStream = socket.getInputStream();
        byte[] buf = new byte[1024];
        int readLen = 0;
        while((readLen = inputStream.read(buf)) != -1) {
            System.out.println(new String(buf, 0, readLen));
        }
        //6. 关闭流对象和socket,必须关闭
        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
public class SocketTCP01Server {
    public static void main(String[] args) throws IOException {
        //1. 在本机的9999端口监听,等待连接
        //   细节: 要求在本机没有其他服务在监听9999
        ServerSocket serverSocket = new ServerSocket(9999);//ServerSocket可以创建多个Socket
        System.out.println("服务端在9999端口监听,等待连接..");
        //2. 当没有客户端连接9999端口时,程序会阻塞,等待连接
        //   如果有客户端连接,则会返回Socket对象,程序继续
        Socket socket = serverSocket.accept();
        System.out.println("服务端 socket = " + socket.getClass());
        //3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据,显示
        InputStream inputStream = socket.getInputStream();
        //4. IO读取
        byte[] buf = new byte[1024];
        int readLen = 0;
        while ((readLen = inputStream.read(buf)) != -1) {
            System.out.println(new String(buf, 0, readLen));
        }
        //5. 获取socket相关的输出流
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello,client".getBytes());
        //6. 设置结束标记
        socket.shutdownOutput();
        //5. 关闭流
        inputStream.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

# 10.4.3 TCP字符流编程

//客户端
public class SocketTCP01Client {
    public static void main(String[] args) throws IOException {
        //1. 连接服务器(ip,端口)
        //链接本机的9999端口,如果连接成功,返回Socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("客户端 socket返回= " + socket.getClass());
        //2. 连接上后,生成Socket,通过socket.getOutputStream()得到和socket对象关联的输出流对象
        OutputStream outputStream = socket.getOutputStream();
        //3. 通过输出流,写入数据到数据通道,使用字符流
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
        bufferedWriter.write("hello, server 字符流");
        bufferedWriter.newLine(); //插入一个换行符,表示写入的内容结束,注意:这样写要要求对方使用readLine()方法读取数据
        bufferedWriter.flush();//如果使用的字符流,需要手动刷新,否则数据不会写入数据通道
        //5. 获取和socket关联的输入流,读取数据(字节)并显示
        InputStream inputStream = socket.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s = bufferedReader.readLine();
        System.out.println(s);


        //6. 关闭流对象和socket,必须关闭
        bufferedReader.close();
        bufferedWriter.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
//服务端
public class SocketTCP01Server {
    public static void main(String[] args) throws IOException {
        //1. 在本机的9999端口监听,等待连接
        //   细节: 要求在本机没有其他服务在监听9999
        ServerSocket serverSocket = new ServerSocket(9999);//ServerSocket可以创建多个Socket
        System.out.println("服务端在9999端口监听,等待连接..");
        //2. 当没有客户端连接9999端口时,程序会阻塞,等待连接
        //   如果有客户端连接,则会返回Socket对象,程序继续
        Socket socket = serverSocket.accept();
        System.out.println("服务端 socket = " + socket.getClass());
        //3. 通过socket.getInputStream() 读取客户端写入到数据通道的数据,显示
        InputStream inputStream = socket.getInputStream();
        //4. IO读取,使用字符流
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s = bufferedReader.readLine();
        System.out.println(s);

        //5. 获取socket相关的输出流
        OutputStream outputStream = socket.getOutputStream();
        //使用字符输出流方式回复信息
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
        bufferedWriter.write("hello client 字符流");
        bufferedWriter.newLine();//插入一个换行符,表示回复内容的结束
        bufferedWriter.flush();//需要手动flush

        //5. 关闭流
        bufferedWriter.close();
        bufferedReader.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

# 10.4.4 TCP网络通信编程应用实例

# 10.4.5 netstat指令

(1)netstat -an 可以查看当前主机网络情况,包括端口监听情况和网络连接情况

(2)netstat -an | more 可以分页显示

# 10.5 UDP网络通信编程

public class UDPReceiverA {
    public static void main(String[] args) throws IOException {
        //1. 创建一个 DatagramSocket 对象,准备在9999接收数据
        DatagramSocket socket = new DatagramSocket(9999);
        //2. 构建一个 DatagramPacket 对象,准备接收数据
        //   在前面讲解UDP协议时,一个数据包最大64k
        byte[] buf = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buf, buf.length);
        //3. 调用接收方法,将通过网络传输的DatagramPacket对象填充到packet对象
        //当有数据包发送到本机的9999端口时,就会接收到数据,如果没有数据包发送到本机的9999端口,就会阻塞等待
        System.out.println("接收端A 等待接收数据");
        socket.receive(packet);

        //可以把packet进行拆包,取出数据并显示
        int length = packet.getLength(); //实际接收到的数据字节长度
        byte[] data = packet.getData(); //接收到的数据
        String s = new String(data, 0, length);
        System.out.println(s);

        //回复信息给B端
        //将需要发送的数据封装到 DatagramPacket对象
        data = "好的, 明天见".getBytes();
        packet = new DatagramPacket(data, data.length, InetAddress.getByName("10.107.32.30"), 9998);
        socket.send(packet);

        socket.close();
        System.out.println("A端退出");
    }
}
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
public class UDPSenderB {
    public static void main(String[] args) throws IOException {
        //创建 DatagramSocket对象,准备在9998端口发送数据
        DatagramSocket socket = new DatagramSocket(9998);

        //将需要发送的数据封装到DatagramPacket对象
        byte[] data = "hello 明天吃火锅".getBytes();
        //封装的DatagramPacket对象data内容是:字节数组, data.length, 主机(ip), 端口
        DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("10.107.32.30"), 9999);

        socket.send(packet);

        //接收从A端回复的信息
        //2. 构建一个 DatagramPacket 对象,准备接收数据
        //   在前面讲解UDP协议时,一个数据包最大64k
        byte[] buf = new byte[1024];
        packet = new DatagramPacket(buf, buf.length);
        //3. 调用接收方法,将通过网络传输的DatagramPacket对象填充到packet对象
        //当有数据包发送到本机的9998端口时,就会接收到数据,如果没有数据包发送到本机的9998端口,就会阻塞等待
        System.out.println("接收端A 等待接收数据");
        socket.receive(packet);

        //可以把packet进行拆包,取出数据并显示
        int length = packet.getLength(); //实际接收到的数据字节长度
        data = packet.getData(); //接收到的数据
        String s = new String(data, 0, length);
        System.out.println(s);

        socket.close();
        System.out.println("B端退出");
    }
}
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

# 10.6 TCP文件下载

//文件下载的客户端
public class Homework03Client {
    public static void main(String[] args) throws Exception {
        //1. 接收用户输入,指定下载文件名
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入下载的文件名");
        String downloadFileName = scanner.next();

        //2. 客户端连接服务器,准备发送
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);

        //3. 获取和Socket关联的输出流
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write(downloadFileName.getBytes());

        //4. 设置结束的标志
        socket.shutdownOutput();

        //5. 读取服务端返回的文件(字节数据)
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        byte[] bytes = StreamUtils.streamToByteArray(bis);

        //6. 得到一个输出流,准备将 bytes 写入到磁盘文件
        String filePath = "d:\\桌面\\" + downloadFileName + ".mp3";
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
        bos.write(bytes);

        //7. 关闭相关的资源
        bos.close();
        bis.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
//先写文件下载的服务端
public class Homework03Server {
    public static void main(String[] args) throws Exception {
        //1. 监听 9999 端口
        ServerSocket serverSocket = new ServerSocket(9999);
        //2. 等待客户端连接
        System.out.println("服务器在9999端口监听等待下载文件");
        Socket socket = serverSocket.accept();
        //3. 读取 客户端发送要下载的文件名
        InputStream inputStream = socket.getInputStream();
        byte[] b = new byte[1024];
        int len = 0;
        String downLoadFileName = "";
        while ((len = inputStream.read(b)) != -1) {
            downLoadFileName += new String(b, 0, len);
        }

        System.out.println("客户端希望下载的文件名 = " + downLoadFileName);
        //在服务器上有两个文件,无名.mp3 高山流水.mp3
        //如果客户下载的是 高山流水 就返回该文件,否则一律返回 无名.mp3

        String resFileName = "";
        if ("高山流水".equals(downLoadFileName)) {
            resFileName = "src\\高山流水.mp3";
        } else {
            resFileName = "src\\无名.mp3";
        }
        //创建一个输入流用来读取文件
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(resFileName));

        //使用工具类StreamUtils,读取文件到一个字节数组
        byte[] bytes = StreamUtils.streamToByteArray(bis);

        //得到与Socket关联的输出流
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

        //写入到数据通道,返回给客户端
        bos.write(bytes);

        //设置结束标记
        socket.shutdownOutput();

        //关闭相关的资源
        bis.close();
        inputStream.close();
        socket.close();
        serverSocket.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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
 * 此类用于演示关于流的读写方法
 *
 */
public class StreamUtils {
	/**
	 * 功能:将输入流转换成byte[], 即可以把文件的内容读入到byte[]
	 */
	public static byte[] streamToByteArray(InputStream is) throws Exception{
		ByteArrayOutputStream bos = new ByteArrayOutputStream();//创建输出流对象
		byte[] b = new byte[1024];//字节数组
		int len;
		while((len=is.read(b))!=-1){//循环读取
			bos.write(b, 0, len);//把读取到的数据,写入bos	
		}
		byte[] array = bos.toByteArray();//然后将bos 转成字节数组
		bos.close();
		return array;
	}

	/**
	 * 功能:将InputStream转换成String
	 */
	public static String streamToString(InputStream is) throws Exception{
		BufferedReader reader = new BufferedReader(new InputStreamReader(is));
		StringBuilder builder= new StringBuilder();
		String line;
		while((line=reader.readLine())!=null){
			builder.append(line+"\r\n");
		}
		return builder.toString();
	}
}
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
最近更新: 3/24/2025, 2:07:09 PM
开发笔记   |