网络编程——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/

运行结果:

相关推荐
我命由我123451 分钟前
Android Studio 问题:Android Studio 一直开在 Updating indexes
android·java·ide·java-ee·android studio·android jetpack·android-studio
hbwhmama15 分钟前
ubuntu24.04安装IDEA2025.1.2搭建java开发环境
java·开发语言
真夜42 分钟前
个人spring-boot问题记录
java·后端
程序员小奕44 分钟前
springboot 百货中心供应链管理系统小程序
java·spring boot·后端
刘白Live1 小时前
【Java】为什么有时候执行countDownLatch+线程池查询列表会丢失数据?
java·后端
剑海风云1 小时前
适应性Java用于现代 API:REST、GraphQL 和事件驱动
java·api·restful·graphql·事件驱动
会飞的架狗师1 小时前
【面试题】如何保证MQ的消息不丢失、不重复
java·面试·kafka·java-rocketmq
蔡蓝2 小时前
设计模式-备忘录模式
java·设计模式·备忘录模式
迢迢星万里灬2 小时前
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
java·spring boot·spring·mybatis·spring mvc·面试指南
只有干货2 小时前
java若依 excel 导出高度自适应
java·excel