• 多线程方式客户端和服务端 代码 看过


    案例: 客户端给服务器端上传一个 文本文件, 多线程版服务器端

    客户端思路:
    1. 创建客户端Socket对象.
    2. 获取可以往服务器端写数据的流.
    3. 将第2步获取到的 字节流 -> 字符流 -> 字符缓冲流.
    4. 创建 高效字符输入流对象, 用来读取 文件文件中的数据.
    5. 具体读写的操作.
    读: 读的是文件中的数据.
    写: 写给服务器端.

    核心操作: 必须给服务器端一个结束标记.

    6. 获取可以读取服务器端回执信息的流.
    7. 将其封装成字符流 -> 字符缓冲流.
    8. 具体的具体回执信息的操作.
    9. 释放资源.
    */
    public class Client {
    public static void main(String[] args) throws Exception {
    //1. 创建客户端Socket对象.
    Socket socket = new Socket("192.168.18.61", 10010);
    //2. 获取可以往服务器端写数据的流.
    //分解版.
    /*OutputStream os = socket.getOutputStream();
    //3. 将第2步获取到的 字节流 -> 字符流 -> 字符缓冲流.
    OutputStreamWriter osw = new OutputStreamWriter(os);
    BufferedWriter bw = new BufferedWriter(osw);*/
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

    //4. 创建 高效字符输入流对象, 用来读取 文件文件中的数据.
    BufferedReader br = new BufferedReader(new FileReader("day14/data/1.txt"));
    //5. 具体读写的操作.
    String line;
    //读: 读的是文件中的数据.
    while ((line = br.readLine()) != null) {
    //写: 写给服务器端.
    bw.write(line);
    bw.newLine();
    bw.flush(); //记得要刷新, 因为bw对象是根据Socket对象创建的, 稍后没有bw.close()代码.
    }
    br.close();

    //这里有问题, 核心操作: 必须给服务器端一个结束标记.
    socket.shutdownOutput();

    //6. 获取可以读取服务器端回执信息的流.
    //7. 将其封装成字符流 -> 字符缓冲流.
    BufferedReader br2 = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    //8. 具体的具体回执信息的操作.
    String resultMessage = br2.readLine();
    System.out.println(resultMessage);

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

    案例: 客户端给服务器端上传一个 文本文件, 多线程版服务器端.

    服务器思路:
    1. 创建服务器端Socket对象.
    2. 监听连接.
    3. 获取可以读取客户端写过来的数据的 流.
    4. 将第3步获取到的 字节流 -> 字符流 -> 字符高效流.
    5. 创建 字符高效输出流对象, 用来往 目的地文件中写数据.
    6. 具体读写的操作
    读: 读的是客户端写过来的数据.
    写: 写到目的地文件中.
    7. 获取可以往客户端写回执信息的流.
    8. 将其封装成 字符流 -> 高效字符流.
    9. 给客户端写回执信息, 记得要刷新.
    10. 释放资源.

    服务器端多线程版本改造计划:
    思路: 客户端代码不动, 服务器端升级为 多线程版.
    1. 自定义资源子类MyRunnable, 实现Runnable接口.
    2. 定义一个变量, 用来表示 Socket对象, 该对象是负责和 客户端Socket交互的对象.
    3. 在构造方法中, 给上述的 成员变量Socket赋值.
    4. 重写run()方法, 把具体上传文件操作的内容, 都Copy过来.
    细节1: 注意, 因为是Runnable#run()方法, 所以有异常只能try, 不能抛.
    细节2: 注意文件名重名问题.
    5. 改造服务器端代码, 把一次监听改为循环监听.
    6. 只要有客户端申请建立连接, 在服务器端审核数据合法后,
    就创建一个 线程对象, 负责和此客户端的交互.

    */
    public class Server {
    public static void main(String[] args) throws Exception{
    //1. 创建服务器端Socket对象.
    ServerSocket server = new ServerSocket(10010);

    //2. 监听连接.
    while(true) {
    //5. 改造服务器端代码, 把一次监听改为循环监听.
    Socket accept = server.accept();
    // 6. 只要有客户端申请建立连接, 在服务器端审核数据合法后,
    // 就创建一个 线程对象, 负责和此客户端的交互.
    //格式: new Thread(Runnable接口的子类对象).start();
    new Thread(new MyRunnable(accept)).start();
    }


    //1. 自定义资源子类MyRunnable, 实现Runnable接口.
    public class MyRunnable implements Runnable{
    //2. 定义一个变量, 用来表示 Socket对象, 该对象是负责和 客户端Socket交互的对象.
    private Socket accept;

    //3. 在构造方法中, 给上述的 成员变量Socket赋值.
    public MyRunnable(Socket accept) { //accept: 该对象是负责和 客户端Socket交互的对象.
    this.accept = accept;
    }

    //4. 重写run()方法, 把具体上传文件操作的内容, 都Copy过来.
    @Override
    public void run() {
    //细节1: 注意, 因为是Runnable#run()方法, 所以有异常只能try, 不能抛.
    //细节2: 注意文件名重名问题.
    int count = 1;
    File file = new File("day14/data/copy(1).txt");
    while (file.exists()) { //判断文件是否存在.
    //如果存在, 就修改文件名
    file = new File("day14/data/copy("+ ++count +").txt");
    }
    try {
    //3. 获取可以读取客户端写过来的数据的 流.
    //4. 将第3步获取到的 字节流 -> 字符流 -> 字符高效流.
    BufferedReader br = new BufferedReader(new InputStreamReader(accept.getInputStream()));
    //5. 创建 字符高效输出流对象, 用来往 目的地文件中写数据.
    BufferedWriter bw = new BufferedWriter(new FileWriter(file));
    //6. 具体读写的操作
    String line;
    //读: 读的是客户端写过来的数据.
    while ((line = br.readLine()) != null) {
    //写: 写到目的地文件中.
    bw.write(line);
    bw.newLine();
    bw.flush(); //记得要刷新, 因为bw对象是根据Socket对象创建的, 稍后没有bw.close()代码.
    }
    bw.close(); //可以先关闭bw对象.

    //7. 获取可以往客户端写回执信息的流.
    //OutputStream os = accept.getOutputStream();
    //8. 将其封装成 字符流 -> 高效字符流.
    //BufferedWriter bw2 = new BufferedWriter(new OutputStreamWriter(os));
    BufferedWriter bw2 = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
    //9. 给客户端写回执信息, 记得要刷新.
    bw2.write("文件上传成功!");
    bw2.newLine();
    bw2.flush();

    //10. 释放资源.
    //br.close();
    accept.close();
    } catch (IOException e) {
    e.printStackTrace();
    } finally {
    }

    分类:
    UDP协议: 类似于: 群聊.
    1. 面向无连接.
    2. 采用 数据报包(DatagramPacket)的形式发送数据, 每个包的大小理论上不能超过 64KB.
    3. 不安全(不可靠)协议.
    4. 效率相对比较高.
    5. 不区分客户端和服务器端, 叫: 发送端和接收端.
    TCP协议: 类似于: 打电话
    1. 面向有连接(三次握手)
    2. 采用IO流的形式发送数据, 理论上无大小限制.
    3. 安全(可靠)协议.
    4. 效率相对比较低.
    5. 区分客户端和服务器端.

  • 相关阅读:
    身份证、姓名、手机号、地址、邮箱脱敏处理
    使用Document解析xml
    java_获取某年开始和结束时间
    java_获取某月开始和结束时间
    java_获取本周开始和结束时间
    java_获取明天开始和结束时间
    java_获取昨天开始和结束时间
    java_获取今天开始和结束时间
    java_给时间加上几天/几小时/几分钟
    在Ue4里面使用自定义鼠标
  • 原文地址:https://www.cnblogs.com/shan13936/p/13904950.html
Copyright © 2020-2023  润新知