网络编程——TCP通信练习

目录

一、多发多收

二、接收和反馈

三、上传文件

四、解决上传文件名重复问题

五、上传文件多线程版

六、上传文件线程池版

七、B/S(接收浏览器的消息并打印)


一、多发多收

客户端:多次发送数据

服务器:接收多次数据,并打印

java 复制代码
public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 10010);
        Scanner scanner = new Scanner(System.in);
        OutputStream os = socket.getOutputStream();
        while (true) {
            System.out.println("请输入内容:");
            String str = scanner.nextLine();
            os.write(str.getBytes());
            if ("拜拜".equals(str)) {
                break;
            }
        }
        socket.close();
    }
}


public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(10010);
        Socket socket = serverSocket.accept();
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        int len;
        while ((len = br.read()) != -1) {
            System.out.print((char) len);
        }
        socket.close();
        serverSocket.close();
    }
}

运行结果:

二、接收和反馈

客户端:发送一条数据,接收服务端反馈的消息并打印

服务器:接收数据并打印,再给客户端反馈消息

java 复制代码
public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 10010);

        // 写出数据
        OutputStream os = socket.getOutputStream();
        String str = "客户端发送消息:见到你很开心!";
        os.write(str.getBytes());

        // 写出结束标记
        socket.shutdownOutput();

        // 读取数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        int len = 0;
        while ((len = br.read()) != -1) {
            System.out.print((char) len);
        }

        // 释放资源
        socket.close();
    }
}

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(10010);
        Socket socket = serverSocket.accept();
        // 读取数据
        // 细节:read方法会从连接通道中读取数据
        //       但是,需要有一个结束标记,此处的循环才会停止,
        //       否则,程序就会一直停在read方法这里,等待读取下面的数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        int len;
        while ((len = br.read()) != -1) {
            System.out.print((char) len);
        }

        // 写出数据
        OutputStream os = socket.getOutputStream();
        String str = "服务器发送消息:有多开心?";
        os.write(str.getBytes());

        // 释放资源
        socket.close();
        serverSocket.close();
    }
}

运行结果:

三、上传文件

客户端:将本地文件上传到服务器,接收服务器的反馈。

服务器:接收客户端上传的文件,上传完毕之后给出反馈。

使用FileInputStream读取本地文件,使用FileOutputStream保存本地文件

java 复制代码
public class Client {
    public static void main(String[] args) throws IOException {
        // 1.创建Socket对象,并连接服务器
        Socket socket = new Socket("127.0.0.1", 10020);
        
        // 2.读取本地文件中的数据,并写到服务器中
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("mysocketnet/clientdir/a.jpg"));
        int len;
        byte[] bytes = new byte[1024];
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
        }

        // 向服务器写出结束标记
        socket.shutdownOutput();

        // 3.接收服务器的回写数据
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String str = br.readLine();
        System.out.println(str);

        // 4.释放资源
        socket.close();
    }
}


public class Server {
    public static void main(String[] args) throws IOException {
        // 1.创建对象并绑定端口
        ServerSocket serverSocket = new ServerSocket(10020);

        // 2.等待客户端来连接
        Socket socket = serverSocket.accept();

        // 3.读取客户端发送的数据,并将数据存入指定路径中
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("mysocketnet/serverdir/a.jpg"));
        int len;
        byte[] bytes = new byte[1024];
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
        }

        // 4. 服务器向客户端回写数据
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bw.write("服务器向客户端发送消息:文件已接收!");
        bw.newLine();
        bw.flush();

        // 5.释放资源
        socket.close();
        serverSocket.close();
    }
}

运行结果:

四、解决上传文件名重复问题

Client代码无需修改

java 复制代码
public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(10020);
        Socket socket = serverSocket.accept();

        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        // 方式一:使用毫秒值拼接
//        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("mysocketnet\\serverdir" + File.separator + System.currentTimeMillis() + ".jpg"));

        // 方式二:使用UUID拼接
        String name = UUID.randomUUID().toString().replace("-", "");
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("mysocketnet\\serverdir" + File.separator + name + ".jpg"));

        int len;
        byte[] bytes = new byte[1024];
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
        }

        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bw.write("文件上传成功!");
        bw.newLine();
        bw.flush();

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

运行结果:

五、上传文件多线程版

让服务器不停止,能接收很多用户上传的图片,可以使用(循环+多线程)

Client代码无需修改

java 复制代码
public class MyRunnable implements Runnable {
    public Socket socket;

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

    @Override
    public void run() {
        try {
            BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
            String name = UUID.randomUUID().toString().replace("-", "");
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("mysocketnet\\serverdir" + File.separator + name + ".jpg"));

            int len;
            byte[] bytes = new byte[1024];
            while ((len = bis.read(bytes)) != -1) {
                bos.write(bytes, 0, len);
            }

            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bw.write("文件上传成功!");
            bw.newLine();
            bw.flush();

        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(10020);

        while (true) {
            // 等待客户端来连接
            Socket socket = serverSocket.accept();

            // 一个用户对应服务端的一条线程
            new Thread(new MyRunnable(socket)).start();
        }
    }
}

先开启Server,每开启一次Client,就会创建一个线程,文件也会上传

运行结果:

六、上传文件线程池版

频繁创建线程并销毁非常浪费系统资源,所以需要用线程池优化。

只需要修改Server即可:

java 复制代码
public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(10020);

        // 创建线程池对象
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
                3, // 核心线程数量
                16, // 线程池总大小
                60, // 空闲时间
                TimeUnit.SECONDS, // 空闲时间(单位)
                new ArrayBlockingQueue<>(2), // 队列
                Executors.defaultThreadFactory(), // 线程工厂,让线程池如何创建线程对象
                new ThreadPoolExecutor.AbortPolicy() // 阻塞队列
        );
        while (true) {
            Socket socket = serverSocket.accept();
//            new Thread(new MyRunnable(socket)).start();
            poolExecutor.submit(new MyRunnable(socket));
        }
    }
}

运行结果:

七、B/S(接收浏览器的消息并打印)

客户端:不需要写

服务器:接收数据并打印

java 复制代码
public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(10010);

        Socket socket = serverSocket.accept();
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        int len;
        char[] chars = new char[1024];
        while ((len = br.read(chars)) != -1) {
            System.out.println(new String(chars, 0, len));
            br.readLine();
        }
        socket.close();
        serverSocket.close();
    }
}

浏览器输入:http://localhost:10010/

运行结果:

相关推荐
佚先森9 分钟前
2024ARM网络验证 支持一键云注入引流弹窗注册机 一键脱壳APP加固搭建程序源码及教程
java·html
古月居GYH22 分钟前
在C++上实现反射用法
java·开发语言·c++
儿时可乖了1 小时前
使用 Java 操作 SQLite 数据库
java·数据库·sqlite
ruleslol1 小时前
java基础概念37:正则表达式2-爬虫
java
xmh-sxh-13141 小时前
jdk各个版本介绍
java
天天扭码2 小时前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
程序猿进阶2 小时前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺2 小时前
Spring Boot框架Starter组件整理
java·spring boot·后端