Java学习_22_网络编程


前言

博客仅记录个人学习进度和一些查缺补漏。
学习内容:BV17F411T7Ao


网络编程

详见408《计算机网络》
在网络通讯协议下,不同的计算机上运行的程序进行数据传输。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

网络编程三要素

在这里插入图片描述

IP

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述C类私有地址192.168.0.0
在这里插入图片描述
在这里插入图片描述

InetAddress

JAVA中提供的ip类,但是没有对外的构造方法,只有先获取自己的IP再更改。
例如:
在这里插入图片描述
也可以根据计算机名字获取:
在这里插入图片描述
例如:获取InetAddress对象
在这里插入图片描述

端口号

在这里插入图片描述
一个端口号只能被一个应用程序使用

协议

计算机网络中,连接和通信的规则被称为网络通信协议

在这里插入图片描述

OSI七层模型

在这里插入图片描述

TCP/IP模型

在这里插入图片描述

UDP协议

在这里插入图片描述
发送数据:
在这里插入图片描述
使用套接字DatagramSocket来发送信息,新建对象的时候需要绑定端口

例如:套接字就是快递小哥,具体的消息内容是将字符数组打包到DatagramPacket,并指定长度、地址和端口号然后,就像填写快递单一样。
在这里插入图片描述
接收数据:
在这里插入图片描述
例如:接收的时候一定要使用对应端口的快递小哥
接收数据也需要使用字符数组
在这里插入图片描述
注意,要先运行接收端,再运行发送端,接收方法receive会自动轮询阻塞等待接收消息,发送端口是随机指定的,并不需要手动指定。
在这里插入图片描述
例如:持续发送直到特殊信息出现
在这里插入图片描述
例如:持续接收
在这里插入图片描述
例如:重复运行多个当前类,形成聊天室
在这里插入图片描述
单播:1对1

组播:1对多

广播:1对全

在这里插入图片描述
例如:组播的实现,需要使用MulticastSocket组播套接字,并且发送的时候需要使用组播地址(组播地址详见计算机网络)

例如:组播的实现,需要让接收端的主机加入组播中
在这里插入图片描述

TCP协议

在这里插入图片描述
TCP再发送数据之前一定要建立连接

在这里插入图片描述
例如:客户端,发出数据(output)释放资源的时候要先关闭链接,再关闭客户端

在这里插入图片描述
例如:服务端,接收数据,会一直轮询accept方法等待链接。
在这里插入图片描述
注意,因为是通过字节流传输,没有指明编码表,所以接受中文的时候会出现乱码

需要在服务器中作出改动,将字节流变成字符流,即转换流
在这里插入图片描述
为增加阅读效率,可以再加入缓冲流

在这里插入图片描述
三次握手,四次挥手,详见408计算机网络。
在这里插入图片描述
在这里插入图片描述

综合练习

多发多收

在这里插入图片描述

package com.itheima.demo7;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class ClientTest {
    public static void main(String[] args) throws IOException {

        Scanner sc = new Scanner(System.in);

        Socket socket = new Socket("127.0.0.1", 10001);
        OutputStream os = socket.getOutputStream();

        // 发送数据
        while (true) {
            System.out.println("发送数据:");
            //注意这个\r\n只有在客户端读取整行时添加,第一种方法不用添加。
            String str = sc.nextLine() + "\r\n";
            if (str.equals("886")) {
                break;
            }
            os.write(str.getBytes());
        }

        os.close();
        socket.close();
    }
}

package com.itheima.demo7;

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

public class ServerTest {
    public static void main(String[] args) throws IOException {
        //本机IP无需指定,只需要指定端口
        //ServerSocket就是本机专属快递员,Socket相当于管道,管道谁都能用,但管道送过来了还得指定的快递员来送达指定端口
        ServerSocket serverSocket = new ServerSocket(10001);

        Socket socket = serverSocket.accept();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        //第一种单字读取
        /*int b;
        while ((b = bufferedReader.read()) != -1) {
            System.out.print((char) b);
        }*/
        //第二种整行读取
        String str = "";
        while ((str = bufferedReader.readLine()) != null){
            System.out.println(str);
        }

        socket.close();
    }
}

接收和反馈

在这里插入图片描述

package com.itheima.demo7;

import java.io.*;
import java.net.Socket;
import java.util.Scanner;

public class ClientTest {
    public static void main(String[] args) throws IOException {

        Scanner sc = new Scanner(System.in);

        Socket socket = new Socket("127.0.0.1", 10001);
        OutputStream os = socket.getOutputStream();

        // 发送数据
        while (true) {
            System.out.println("发送数据:");
            String str = sc.nextLine() + "\r\n";
            if (str.equals("886\r\n")) {
                break;
            }
            os.write(str.getBytes());
        }

        //结束标记
        socket.shutdownOutput();
        
        //接收反馈并输出
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String res = "";
        while ((res = bufferedReader.readLine()) != null) {
            System.out.println(res);
        }

        os.close();
        socket.close();
    }
}

package com.itheima.demo7;

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

public class ServerTest {
    public static void main(String[] args) throws IOException {
        //本机IP无需指定,只需要指定端口
        //ServerSocket就是本机专属快递员,Socket相当于管道,管道谁都能用,但管道送过来了还得指定的快递员来送达指定端口
        ServerSocket serverSocket = new ServerSocket(10001);

        Socket socket = serverSocket.accept();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        String str = "";
        while ((str = bufferedReader.readLine()) != null){
            System.out.println(str);
        }
        System.out.println("接收已结束");

        //发送反馈
        String res = "服务已结束\r\n";
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write(res.getBytes());

        socket.close();
    }
}

上传文件

在这里插入图片描述

package com.itheima.demo7;

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

public class ClientTest {
    public static void main(String[] args) throws IOException {

        Socket socket = new Socket("127.0.0.1", 10001);

        // 发送文件数据
        String ori_path = "F:\\abc\\def\\aaa.jpg";
        File ori_file = new File(ori_path);
        sentFile(ori_file, socket);

        //接收反馈并输出
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String res = bufferedReader.readLine();
        System.out.println(res);

        socket.close();
    }

    public static void sentFile(File file, Socket socket) throws IOException {
        if(file.isFile()) {
            // 读取文件内容(buffer字节流)
            BufferedInputStream bfi = new BufferedInputStream(new FileInputStream(file));
            // 创建发送字节流
            BufferedOutputStream bfo = new BufferedOutputStream(socket.getOutputStream());

            int len;
            byte[] bytes = new byte[1024];
            while ((len = bfi.read(bytes)) != -1) {
                bfo.write(bytes, 0, len);
            }
            // 记住一定要刷新
            bfo.flush();

            //文件结束标记
            socket.shutdownOutput();
            //bfo.close();
        }
    }

}

package com.itheima.demo7;

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

public class ServerTest {
    public static void main(String[] args) throws IOException {
        //本机IP无需指定,只需要指定端口
        //ServerSocket就是本机专属快递员,Socket相当于管道,管道谁都能用,但管道送过来了还得指定的快递员来送达指定端口
        ServerSocket serverSocket = new ServerSocket(10001);

        //持续监听,有人链接就把对方的套接字拿出来
        Socket socket = serverSocket.accept();

        //创建读者输入流
        BufferedInputStream bfi = new BufferedInputStream(socket.getInputStream());

        //创建写者输出流,指定位置
        BufferedOutputStream bfo = new BufferedOutputStream(new FileOutputStream("F:\\abc\\bbb.jpg"));

        int len;
        byte[] bytes = new byte[1024];
        while ((len = bfi.read(bytes)) != -1) {
            bfo.write(bytes, 0, len);
        }
        //记住一定要刷新
        bfo.flush();

        System.out.println("接收已结束");

        //发送反馈
        String res = "服务已结束\r\n";
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write(res.getBytes());

        socket.close();
        serverSocket.close();
    }
}

上传文件重名问题

在这里插入图片描述
使用UUID实现

        //创建写者输出流,指定位置
        String name = UUID.randomUUID().toString().replace("-", "");
        BufferedOutputStream bfo = new BufferedOutputStream(new FileOutputStream("F:\\abc\\" + name +".jpg"));

上传文件多线程问题

在这里插入图片描述

package com.itheima.demo7;

import java.io.*;
import java.net.Socket;
import java.util.UUID;

public class ServerRunnable implements Runnable{

    private Socket socket;

    public ServerRunnable(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            // 创建读者输入流
            BufferedInputStream bfi = new BufferedInputStream(socket.getInputStream());

            // 创建写者输出流,指定位置
            String name = UUID.randomUUID().toString().replace("-", "");
            BufferedOutputStream bfo = new BufferedOutputStream(new FileOutputStream("F:\\abc\\" + name +".jpg"));

            int len;
            byte[] bytes = new byte[1024];
            while ((len = bfi.read(bytes)) != -1) {
                bfo.write(bytes, 0, len);
            }
            // 记住一定要刷新
            bfo.flush();

            System.out.println("接收已结束");

            // 发送反馈
            String res = "服务已结束\r\n";
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write(res.getBytes());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                if (socket != null){
                    socket.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

package com.itheima.demo7;

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

public class ServerTest {
    public static void main(String[] args) throws IOException {
        // 本机IP无需指定,只需要指定端口
        // ServerSocket就是本机专属快递员,Socket相当于管道,管道谁都能用,但管道送过来了还得指定的快递员来送达指定端口
        ServerSocket serverSocket = new ServerSocket(10001);

        while (true) {
            // 持续监听,有人链接就把对方的套接字拿出来
            Socket socket = serverSocket.accept();

            new Thread(new ServerRunnable(socket)).start();
        }

        // 服务器关闭
        //serverSocket.close();
    }
}

package com.itheima.demo7;

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

public class ClientTest {
    public static void main(String[] args) throws IOException {
		// 创建套接字
        Socket socket = new Socket("127.0.0.1", 10001);

        // 发送文件数据
        String ori_path = "F:\\abc\\def\\aaa.jpg";
        File ori_file = new File(ori_path);
        sentFile(ori_file, socket);

        // 接收反馈并输出
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String res = bufferedReader.readLine();
        System.out.println(res);

        socket.close();
    }

    public static void sentFile(File file, Socket socket) throws IOException {
        if(file.isFile()) {
            // 读取文件内容(buffer字节流)
            BufferedInputStream bfi = new BufferedInputStream(new FileInputStream(file));
            // 创建发送字节流
            BufferedOutputStream bfo = new BufferedOutputStream(socket.getOutputStream());

            int len;
            byte[] bytes = new byte[1024];
            while ((len = bfi.read(bytes)) != -1) {
                bfo.write(bytes, 0, len);
            }
            // 记住一定要刷新
            bfo.flush();

            // 文件结束标记
            socket.shutdownOutput();
            // 注意bfo是通过套接字创建的,关闭bfo会导致套接字关闭
            //bfo.close();
        }
    }

}

上传文件线程池问题

在这里插入图片描述

package com.itheima.demo7;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;

public class ServerTest {
    public static void main(String[] args) throws IOException {
        //本机IP无需指定,只需要指定端口
        //ServerSocket就是本机专属快递员,Socket相当于管道,管道谁都能用,但管道送过来了还得指定的快递员来送达指定端口
        ServerSocket serverSocket = new ServerSocket(10001);

        // 定义线程池
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3 // 最大核心线程数
        , 16 // 最大总线程数
        , 60 // 临时线程存活时间
        , TimeUnit.SECONDS // 时间单位
        , new ArrayBlockingQueue<>(3) // 等待队列大小
        , Executors.defaultThreadFactory()  // 线程工厂
        , new ThreadPoolExecutor.AbortPolicy()); // 阻塞队列处理方式

        while (true) {
            //持续监听,有人链接就把对方的套接字拿出来
            Socket socket = serverSocket.accept();

            //提交任务给线程队列(工会)
            threadPoolExecutor.submit(new ServerRunnable(socket));
        }
    }
}

BS架构

在这里插入图片描述

package com.itheima.demo7;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketTest {
    public static void main(String[] args) throws IOException {

        // 创建服务器套接字
        ServerSocket ss = new ServerSocket(10001);
        // 监听等待套接字
        Socket s = ss.accept();

        // 有套接字连接后,接收套接字的输出
        BufferedInputStream bfi = new BufferedInputStream(s.getInputStream());

        int b;
        while ((b = bfi.read()) != -1) {
            System.out.print((char)b);
        }

        s.close();
        ss.close();
    }
}

总结

以前学套接字的时候完全搞不懂,怎么都写不出来就想着赶紧搞完赶紧出去玩,最后网上抄了一个,还不会运行,现在全心全意写代码学习感觉就完全不一样的,心态真的很关键。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值