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

运行结果:

相关推荐
青莳吖几秒前
Java通过Map实现与SQL中的group by相同的逻辑
java·开发语言·sql
Buleall7 分钟前
期末考学C
java·开发语言
重生之绝世牛码9 分钟前
Java设计模式 —— 【结构型模式】外观模式详解
java·大数据·开发语言·设计模式·设计原则·外观模式
小蜗牛慢慢爬行15 分钟前
有关异步场景的 10 大 Spring Boot 面试问题
java·开发语言·网络·spring boot·后端·spring·面试
新手小袁_J40 分钟前
JDK11下载安装和配置超详细过程
java·spring cloud·jdk·maven·mybatis·jdk11
呆呆小雅41 分钟前
C#关键字volatile
java·redis·c#
Monly2141 分钟前
Java(若依):修改Tomcat的版本
java·开发语言·tomcat
Ttang2343 分钟前
Tomcat原理(6)——tomcat完整实现
java·tomcat
钱多多_qdd1 小时前
spring cache源码解析(四)——从@EnableCaching开始来阅读源码
java·spring boot·spring
waicsdn_haha1 小时前
Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】
java·运维·服务器·开发语言·windows·后端·jdk