第16章_网络编程拓展练习(TCP编程,UDP编程)

news2024/12/23 12:14:58

文章目录

  • 第16章_网络编程拓展练习
    • TCP编程
      • 1、学生与老师交互
      • 2、查询单词
      • 3、拓展:查询单词
      • 4、图片上传
      • 5、拓展:图片上传
      • 6、多个客户端上传文件
      • 7、群聊
    • UDP编程
      • 8、群发消息

第16章_网络编程拓展练习


TCP编程

1、学生与老师交互

案例:客户端模拟学生咨询,服务器端模拟咨询老师,进行交互。

客户端收到信息:

​ 欢迎咨询尚硅谷!

​ 这个月的所有期班都已经满了,只能报下一个月的了!

在这里插入图片描述

服务器端收到信息:

​ 你好,我想报名这个月的JavaEE就业班!

​ 好的,赶紧给我占个座!

在这里插入图片描述

提示:

(1)如果是一个客户端与服务器端交互,怎么实现

(2)如果是多个客户端与服务器交互,怎么实现

package com.atguigu.exercise1;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;

public class Exercise1Client {
    public static void main(String[] args) {
        Socket socket = null; // 创建Socket指定ip地址和端口号
        PrintStream ps = null;
        try {
            socket = new Socket("127.0.0.1", 8888);
            // 获取输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println(br.readLine());

            // 获取输出流
            ps = new PrintStream(socket.getOutputStream());
            ps.println("你好,我想报名这个月的JavaEE就业班!");

            System.out.println(br.readLine());

            ps.println("好的,赶紧给我占个座!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ps != null)
                ps.close();
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

(1)服务端接收1个客户端访问

package com.atguigu.exercise1;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.time.LocalDateTime;

public class Exercise1Server {
    public static void main(String[] args) {
        ServerSocket server = null;
        Socket socket = null;
        try {
            server = new ServerSocket(8888);
            socket = server.accept();

            // 获取输出流
            PrintStream ps = new PrintStream(socket.getOutputStream());
            ps.println("欢迎咨询尚硅谷!");

            // 获取输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println(socket.getInetAddress().getHostAddress() + "留言:" + LocalDateTime.now());
            System.out.println(br.readLine() + "\n");

            ps.println("这个月的所有期班都已经满了,只能报下一个月的了!");

            System.out.println(socket.getInetAddress().getHostAddress() + "留言:" + LocalDateTime.now());
            System.out.println(br.readLine());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (socket != null)
                    socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (server != null)
                    server.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

(2)服务端接收多个客户端访问

package com.atguigu.exercise1;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.time.LocalDateTime;

public class Exercise1 {
	public static void main(String[] args) {
        ServerSocket server = null;
        try {
            server = new ServerSocket(8888);
            boolean flag = true;
            while (flag) {
                Socket socket = server.accept();
                new Thread() {
                    public void run() {
                        try {
                            // 获取输出流
                            PrintStream ps = new PrintStream(socket.getOutputStream());
                            ps.println("欢迎咨询尚硅谷");

                            // 获取输入流
                            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                            System.out.println(socket.getInetAddress().getHostAddress() + "留言:" + LocalDateTime.now());
                            System.out.println(br.readLine() + "\n");

                            ps.println("这个月的所有期班都已经满了,只能报下一个月的了!");

                            System.out.println(socket.getInetAddress().getHostAddress() + "留言:" + LocalDateTime.now());
                            System.out.println(br.readLine());

                            socket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (server != null)
                    server.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

2、查询单词

案例:模拟客户端输入要查询的中文,服务器返回对应的英文单词

效果如下:

在这里插入图片描述

在这里插入图片描述

开发提示:

(1)服务器端有一个map,key是中文词语,value是对应的单词

(2)服务器接收到客户端的词语后,从map中get,如果可以找到,就返回单词,如果找不到,就返回“没有找到”

package com.atguigu.exercise2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;

public class Exercise2Server {
	public static void main(String[] args) {
        ServerSocket server = null;
        Socket socket = null;
        try {
            HashMap<String, String> dictionary = new HashMap<String, String>();
            dictionary.put("星期一", "Monday");
            dictionary.put("星期二", "Tuesday");
            dictionary.put("星期三", "Wednesday");
            dictionary.put("星期四", "Thursday");
            dictionary.put("星期五", "Friday");
            dictionary.put("星期六", "Saturday");
            dictionary.put("星期七", "Sunday");
            //...

            server = new ServerSocket(8888);
            socket = server.accept();

            // 获取输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            // 获取输出流
            PrintStream ps = new PrintStream(socket.getOutputStream());

            //接收客户端的中文
            String key = br.readLine();
            //查询对应的英文单词,并返回结果
            String words = dictionary.get(key);
            if (words != null) {
                ps.println(words);
            } else {
                ps.println("o(╥﹏╥)o没有找到对应的单词!");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (socket != null)
                    socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (server != null)
                    server.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

package com.atguigu.exercise2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

public class Exercise2Client {
	public static void main(String[] args) {
        Socket socket = null;
        Scanner input = null;
        try {
            // 创建Socket指定ip地址和端口号
            socket = new Socket("127.0.0.1", 8888);

            input = new Scanner(System.in);
            System.out.print("请输入要查询的词语:");
            String content = input.next();

            // 获取输出流
            PrintStream ps = new PrintStream(socket.getOutputStream());
            ps.println(content);

            // 获取输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println("查询结果:" + br.readLine());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (socket != null)
                    socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (input != null)
                input.close();
        }

    }
}

3、拓展:查询单词

修改前一个题目,改为并发版。

服务器端:

package com.atguigu.exercise3;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;

public class Exercise3Server {
    private static HashMap<String, String> dictionary = new HashMap<String, String>();

    static {
        dictionary.put("星期一", "Monday");
        dictionary.put("星期二", "Tuesday");
        dictionary.put("星期三", "Wednesday");
        dictionary.put("星期四", "Thursday");
        dictionary.put("星期五", "Friday");
        dictionary.put("星期六", "Saturday");
        dictionary.put("星期七", "Sunday");
    }

    public static void main(String[] args) {
        ServerSocket server = null;
        try {
            server = new ServerSocket(8888);

            while (true) {
                Socket socket = server.accept();
                new QueryThread(socket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (server != null)
                    server.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static class QueryThread extends Thread {
        Socket socket;

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

        @Override
        public void run() {
            BufferedReader br = null;
            PrintStream ps = null;
            try {
                // 获取输入流
                br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                // 获取输出流
                ps = new PrintStream(socket.getOutputStream());

                //接收客户端的中文
                String key = br.readLine();
                //查询对应的英文单词,并返回结果
                String words = dictionary.get(key);
                if (words != null) {
                    ps.println(words);
                } else {
                    ps.println("o(╥﹏╥)o没有找到对应的单词!");
                }
            } catch (IOException e) {
                e.printStackTrace();
                ;
            } finally {
                try {
                    if (br != null)
                        br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (ps != null)
                    ps.close();
                try {
                    if (socket != null)
                        socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

客户端:

package com.atguigu.exercise3;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

public class Exercise3Client {
    public static void main(String[] args) {
        Socket socket = null;
        Scanner input = null;
        PrintStream ps = null;
        BufferedReader br = null;
        try {
            // 创建Socket指定ip地址和端口号
            socket = new Socket("127.0.0.1", 8888);

            input = new Scanner(System.in);
            System.out.print("请输入要查询的词语:");
            String content = input.next();

            // 获取输出流
            ps = new PrintStream(socket.getOutputStream());
            ps.println(content);

            // 获取输入流
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println("查询结果:" + br.readLine());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ps != null)
                ps.close();
            try {
                if (br != null)
                    br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (socket != null)
                    socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (input != null)
                input.close();
        }
    }
}

4、图片上传

案例:客户端给服务器端上传照片

要求:

(1)客户端上传的照片,需要是jpg格式的,并且大小在2M(含)以内的,否则不能上传

(2)要求上传成功后,服务器要返回上传成功,如果上传失败,服务器返回上传失败

(3)客户端上传到服务器端的照片,存储在项目名下"photo"的文件夹中,并且以“照片原文件名+时间戳.jpg”命名

效果如下:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

package com.atguigu.exercise4;

import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Exercise4Server{
	public static void main(String[] args) {
        ServerSocket server = null;
        Socket socket = null;
        DataInputStream dis = null;
        PrintStream ps = null;
        FileOutputStream fos = null;
        try {
            //开启服务器
            server = new ServerSocket(8888);
            //接收一个客户端的连接
            socket = server.accept();
            //获取输入流
            dis = new DataInputStream(socket.getInputStream());
            //获取输出流
            ps = new PrintStream(socket.getOutputStream());
            //(1)先读取文件名
            String filename = dis.readUTF();

            //(2)生成唯一的文件名
            String destfile = "photo" + "/" + filename + System.currentTimeMillis() + ".jpg";

            //(3)读取文件内容,并写入目标文件
            fos = new FileOutputStream(destfile);
            try {
                byte[] data = new byte[1024];
                int len;
                while ((len = dis.read(data)) != -1) {
                    fos.write(data, 0, len);
                }
                //返回结果给客户端
                ps.println("接收成功!");
            } catch (Exception e) {
                //返回结果给客户端
                ps.println("接收失败!");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fos != null)
                    fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            ps.close();
            try {
                if (dis != null)
                    dis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (socket != null)
                    socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (server != null)
                    server.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
package com.atguigu.exercise4;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.Scanner;

public class Exercise4Client {
	public static void main(String[] args)throws IOException {
        //连接服务器
        Socket socket= new Socket("127.0.0.1",8888);

        //选择要上传的文件
        Scanner input = new Scanner(System.in);
        System.out.println("请选择要上传的文件:");
        //例如:D:\尚硅谷_0325班_柴林燕_JavaSE\笔记\第14章 IO流.docx
        String fileStr  = input.nextLine();
        File file = new File(fileStr);

        if(!fileStr.endsWith(".jpg")){
            System.out.println("照片必须是.jpg格式");
            input.close();
            socket.close();
            return;
        }
        if(file.length()>1024*1024*2){
            System.out.println("照片必须在2M(含)以内");
            input.close();
            socket.close();
            return;
        }

        DataOutputStream dos = null;
        //从file读取内容,给服务器发送
        FileInputStream fis = null;
        try {
            //获取输出流
            dos = new DataOutputStream(socket.getOutputStream());
            //先发送文件名
            dos.writeUTF(file.getName().substring(0, file.getName().lastIndexOf(".")));
            //发送文件内容
            fis = new FileInputStream(file);
            byte[] data = new byte[1024];
            int len;
            while((len = fis.read(data)) !=-1){
                dos.write(data, 0, len);
            }
            socket.shutdownOutput();//告诉服务器,我发送完毕
        } catch (Exception e) {
            System.out.println("上传失败");
        }finally{
            fis.close();
            dos.close();
        }

        //接收结果
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String result = br.readLine();
        System.out.println(result);

        br.close();
        socket.close();
        input.close();
    }

}

5、拓展:图片上传

相较于上题,修改为并发版。

服务器端:

package com.atguigu.exercise5;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Exercise5Server {
    public static void main(String[] args) {
        ServerSocket server = null;
        try {
            //开启服务器
            server = new ServerSocket(8888);
            while (true) {
                //接收一个客户端的连接
                Socket socket = server.accept();
                new UploadPhotoThread(socket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (server != null)
                    server.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static class UploadPhotoThread extends Thread {
        Socket socket;

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

        @Override
        public void run() {
            try (
                    //获取输入流
                    ObjectInputStream dis = new ObjectInputStream(socket.getInputStream());
                    //获取输出流
                    PrintStream ps = new PrintStream(socket.getOutputStream());
            ){
                //(1)先读取文件名
                String filename = dis.readUTF();

                //(2)生成唯一的文件名
                String destfile = "photo" + "/" + filename + System.currentTimeMillis() + ".jpg";

                //(3)读取文件内容,并写入目标文件
                FileOutputStream fos = null;
                try {
                    fos = new FileOutputStream(destfile);
                    byte[] data = new byte[1024];
                    int len;
                    while ((len = dis.read(data)) != -1) {
                        fos.write(data, 0, len);
                    }
                    //返回结果给客户端
                    ps.println("接收成功!");
                } catch (Exception e) {
                    //返回结果给客户端
                    ps.println("接收失败!");
                } finally {
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

客户端:

package com.atguigu.exercise5;

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

public class Exercise5Client {
    public static void main(String[] args) throws IOException {
        //连接服务器
        Socket socket = new Socket("127.0.0.1", 8888);

        //选择要上传的文件
        Scanner input = new Scanner(System.in);
        System.out.println("请选择要上传的文件:");
        //例如:D:\尚硅谷_0325班_柴林燕_JavaSE\笔记\第14章 IO流.docx
        String fileStr = input.nextLine();
        File file = new File(fileStr);

        if (!fileStr.endsWith(".jpg")) {
            System.out.println("照片必须是.jpg格式");
            input.close();
            socket.close();
            return;
        }
        if (file.length() > 1024 * 1024 * 2) {
            System.out.println("照片必须在2M(含)以内");
            input.close();
            socket.close();
            return;
        }

        //获取输出流
        ObjectOutputStream dos = new ObjectOutputStream(socket.getOutputStream());
        //先发送文件名
        dos.writeUTF(file.getName().substring(0, file.getName().lastIndexOf(".")));

        //从file读取内容,给服务器发送
        FileInputStream fis = new FileInputStream(file);


        //发送文件内容
        byte[] data = new byte[1024];
        int len;
        while ((len = fis.read(data)) != -1) {
            dos.write(data, 0, len);
        }
        socket.shutdownOutput();//告诉服务器,我发送完毕


        //接收结果
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String result = br.readLine();
        System.out.println(result);

        fis.close();
        dos.close();
        br.close();
        socket.close();
        input.close();
    }

}

6、多个客户端上传文件

需求:每一个客户端启动后都可以给服务器上传一个文件;服务器接收到文件后保存到一个upload目录中,可以同时接收多个客户端的文件上传。

思考分析:

(1)服务器端要“同时”处理多个客户端的请求,那么必须使用多线程,每一个客户端的通信需要单独的线程来处理。

(2)服务器保存上传文件的目录只有一个upload,而每个客户端给服务器发送的文件可能重名,所以需要保证文件名的唯一。我们可以使用“时间戳”作为文件名,而后缀名不变

(3)客户端需要给服务器上传文件名(含后缀名)以及文件内容。而文件名是字符串,文件内容不一定是纯文本的,因此选择ObjectOutputStream 和 ObjectInputStream。

服务器示例代码:

package com.atguigu.exercise6;

import java.net.ServerSocket;
import java.net.Socket;

public class Exercise6Server {
    public static void main(String[] args) {
        ServerSocket server = null;
        try {
            //服务器在8888端口号监听数据
            server = new ServerSocket(8888);

            while (true) {
                //(2)等待连接
                //这句代码执行一次,意味着一个客户端连接
                Socket accept = server.accept();

                FileUploadThread ft = new FileUploadThread(accept);
                ft.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (server != null)
                    server.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
package com.atguigu.exercise6;

import java.io.*;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;

public class FileUploadThread extends Thread {
    private Socket socket;
    private String dir = "upload/";//可以把它放到配置文件中

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

    public void run() {
        FileOutputStream fos = null;
        ObjectInputStream dis = null;
        PrintStream ps = null;
        try {
            InputStream is = socket.getInputStream();
            dis = new ObjectInputStream(is);

            OutputStream out = socket.getOutputStream();
            ps = new PrintStream(out);

            //读取文件名(含后缀名)
            String filename = dis.readUTF();
            int lastIndexOfDot = filename.lastIndexOf(".");
            //截取后缀名
            String ext = filename.substring(lastIndexOfDot);
            //生成时间戳
            SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
            //拼接新文件名 = 旧文件名 + 时间戳 + 后缀名
            String newFilename = filename.substring(0, lastIndexOfDot) + sf.format(new Date()) + ext;
            //拼接文件路径
            String pathname = dir + File.separator + newFilename;
            //用新文件路径构建文件输出流
            fos = new FileOutputStream(pathname);
            //接收文件内容
            byte[] data = new byte[1024];
            long sum = 0;
            int len;
            while ((len = dis.read(data)) != -1) {
                fos.write(data, 0, len);
                fos.flush();
                sum += len;
            }
            System.out.println("sum = " + sum);

            //返回结果
            ps.println(filename + "已上传完毕");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                fos.close();

            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                if (dis != null)
                    dis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (ps != null)
                ps.close();

            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

客户端示例代码:

package com.atguigu.exercise6;

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

public class Exercise6Client {
    public static void main(String[] args) {
        // (1)连接服务器
        Socket socket = null;

        FileInputStream fis = null;
        ObjectOutputStream dos = null;
        OutputStream out = null;
        Scanner input = null;
        BufferedReader br = null;

        try {
            socket = new Socket("127.0.0.1", 8888);
            input = new Scanner(System.in);

            out = socket.getOutputStream();
            // 用它的目的是为了既可以单独传一个字符串,又可以写字节内容
            dos = new ObjectOutputStream(out);

            InputStream is = socket.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);// 把字节流转成字符流
            br = new BufferedReader(isr);

            // (2)从键盘输入文件的路径和名称
            System.out.print("请选择要上传的文件:");
            String path = input.nextLine();
            File file = new File(path);

            // 先发送文件名(含后缀名)
            dos.writeUTF(file.getName());// 单独发一个字符串

            // 还需要一个IO流,从文件读取内容,给服务器发过去
            fis = new FileInputStream(file);
            // (3)把文件内容给服务器传过去,类似与复制文件
            byte[] data = new byte[1024];
            int len;
            long sum = 0;
            while ((len = fis.read(data)) != -1) {
                dos.write(data, 0, len);
                sum += len;
                dos.flush();
            }
            System.out.println("sum = " + sum);
            socket.shutdownOutput();//数据发送完毕,不再发送,但是还要接收,所以是半关闭

            // (4)接收服务器返回的结果
            String result = br.readLine();
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            // (5)关闭
            try {
                if (fis != null)
                    fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (dos != null)
                    dos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (out != null)
                    out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (input != null)
                input.close();
            try {
                if (br != null)
                    br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (socket != null)
                    socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

7、群聊

需求:客户端与服务器连接成功后,就可以看到其他客户端的发送的聊天信息,当前客户端也可以发送自己的聊天信息。

思考分析:

(1)服务器

要同时接收多个客户端的连接,因此需要多线程

服务器这边充当转发角色,即在服务器这边的某个客户端的Socket接收到自己客户端发送的消息后,要通过服务器端这边其他客户端的Socket将信息转发出去

(2)客户端

同时能够接收和发送消息,因此也要两个线程,一个接收,一个发送

在这里插入图片描述

服务器端示例代码:

package com.atguigu.exercise7;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;

public class Exercise7Server {
    private static ArrayList<Socket> online = new ArrayList<Socket>();

    public static void main(String[] args) {
        ServerSocket server = null;
        try {
            //1、开启服务器
            server = new ServerSocket(9999);

            while (true) {
                //2、接收客户端的连接
                Socket socket = server.accept();

                //把这个客户端加入到online中
                online.add(socket);

                //每一个客户端独立的线程
                MessageHandler mh = new MessageHandler(socket);
                mh.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (server != null)
                    server.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    private static class MessageHandler extends Thread {
        private Socket socket;
        private String ip;

        public MessageHandler(Socket socket) {
            super();
            this.socket = socket;
            this.ip = socket.getInetAddress().getHostAddress();
        }

        public void run() {
            BufferedReader br = null;
            PrintStream ps = null;
            try {
                //接收当前的客户端发送的消息
                InputStream in = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(in);
                br = new BufferedReader(isr);

                //这个客户端的一连接成功,线程一启动,就可以告诉其他人我上线了
                sendToOthers(ip + "上线了");
                while (true) {
                    String content = br.readLine();
                    if (content == null) {
                        break;
                    }
                    //收到一句,转发一句
                    sendToOthers(ip + "说:" + content);

                    if ("bye".equals(content)) {
                        //给自己发一句bye
                        OutputStream out = socket.getOutputStream();
                        ps = new PrintStream(out);
                        ps.println("bye");
                        break;
                    }
                }
                sendToOthers(ip + "下线了");
            } catch (IOException e) {
                sendToOthers(ip + "掉线了");
            } finally {
                try {
                    if (socket != null)
                        socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                try {
                    if (br != null)
                        br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (ps != null)
                    ps.close();
            }
        }

        //因为转发的代码也很长,独立为一个方法
        public void sendToOthers(String str) {
            //遍历所有online的客户端
            Iterator<Socket> iterator = online.iterator();
            while (iterator.hasNext()) {
                Socket on = iterator.next();
                if (!on.equals(socket)) {//只给其他客户端转发
                    try {
                        OutputStream out = on.getOutputStream();
                        PrintStream ps = new PrintStream(out);
                        //不能用try(){}catch,因为这里不能关闭流和其他socket

                        ps.println(str);
                    } catch (IOException e) {
                        //说明on这个客户端要么下线了,要么掉线了
                        iterator.remove();
                    }
                }
            }
        }
    }
}

客户端示例代码:

package com.atguigu.exercise7;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;


public class Exercise7Client {
    public static void main(String[] args) {
        Socket socket = null;
        try {
            // 1、连接服务器
            socket = new Socket("127.0.0.1", 9999);

            // 2、开启两个线程,一个收消息,一个发消息
            SendThread st = new SendThread(socket);
            ReceiveThread rt = new ReceiveThread(socket);

            st.start();
            rt.start();

            // 等发送线程停下来再往下走
            st.join();
            rt.interrupt();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //关闭socket
            try {
                if (socket != null)
                    socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    static class SendThread extends Thread {
        private Socket socket;

        public SendThread(Socket socket) {
            super();
            this.socket = socket;
        }

        public void run() {
            Scanner input = null;
            PrintStream ps = null;
            try {
                // 键盘输入
                input = new Scanner(System.in);
                OutputStream out = socket.getOutputStream();
                ps = new PrintStream(out);
                while (true) {
                    // 从键盘输入
                    System.out.print("请输入要发送的消息:");
                    String content = input.nextLine();

                    // 给服务器发送
                    ps.println(content);

                    // 如果bye,就结束发送
                    if ("bye".equals(content)) {
                        break;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (input != null)
                    input.close();
                if (ps != null)
                    ps.close();
            }
        }
    }

    static class ReceiveThread extends Thread {
        private Socket socket;

        public ReceiveThread(Socket socket) {
            super();
            this.socket = socket;
        }

        public void run() {
            BufferedReader br = null;
            try {
                InputStream in = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(in);
                br = new BufferedReader(isr);
                while (true) {
                    String line = br.readLine();
                    if ("bye".equals(line)) {
                        break;
                    }
                    System.out.println(line);
                }
            } catch (SocketException e) {
                System.out.println("退出");
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (br != null) {
                    try {
                        br.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

UDP编程

8、群发消息

案例:模拟给全部同学群发“欢迎来到尚硅谷”

开发提示:使用UDP群发

package com.atguigu.exercise8;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class Exercise8Send {
	public static void main(String[] args) {
        DatagramSocket ds = null;
        try {
            //(1)先建立一个DatagramSocket
            ds = new DatagramSocket();

            //(2)准备发送的数据
            String str = "欢迎来到尚硅谷";
            byte[] data = str.getBytes();

            for (int i = 0; i <= 255; i++) {
                //(3)把数据包装成一个数据报
                //DatagramPacket(byte[] buf, int length, InetAddress address, int port)
                /*
                 * 第一个参数:要发送的数据的字节数组
                 * 第二个参数:数组的长度
                 * 第三个参数:接收方的IP地址
                 * 第三个参数:接收方的端口号
                 *
                 * 好比发快递,需要填写接收方的IP和端口号
                 */
                InetAddress ip = InetAddress.getByName("192.168.11." + i);
                int port = 8888;
                DatagramPacket dp = new DatagramPacket(data, data.length, ip, port);


                //(4)发送数据报
                // 通过socket发送
                ds.send(dp);

            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //(5)断开
            if (ds != null)
                ds.close();
        }
    }
}

package com.atguigu.exercise8;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Exercise8Receiver {
	public static void main(String[] args) {
        DatagramSocket ds = null;
        try {
            //1、准备一个socket,用来接收消息
            //接收方,先确定端口号,监听数据的端口号
            //好比,要收到快递,需要先确定自己的地址和手机号,然后对方才能给你发
            ds = new DatagramSocket(8888);

            //2、准备一个数据报,来接收数据
            //DatagramPacket(byte[] buf, int length)
            byte[] data = new byte[1024 * 64];//64K
            DatagramPacket dp = new DatagramPacket(data, data.length);

            //3、接收数据
            ds.receive(dp);

            //4、拆包裹
            byte[] result = dp.getData();
            int len = dp.getLength();//实际接收的数据的长度
            System.out.println(new String(result, 0, len));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //5、关闭
            if (ds != null)
                ds.close();
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1405062.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue的模板语法-指令-事件绑定-条件渲染

VSCode代码片段生成 我们在前面练习Vue的过程中&#xff0c;有些代码片段是需要经常写的&#xff0c;我们再VSCode中我们可以生成一个代码片段&#xff0c;方便我们快速生成。 VSCode中的代码片段有固定的格式&#xff0c;所以我们一般会借助于一个在线工具来完成。 具体的步…

前端模板字符串的使用

目录 1.说明 2.示例 3.总结 1.说明 模板字符串是用反引号&#xff08;&#xff09;分隔的字面量&#xff0c;允许多行字符串&#xff0c;带有嵌入表达式的字符串插值和一种带标签的模板的特殊结构。 是增强版的字符串&#xff0c;在进行字符串拼接时&#xff0c;可以拼接固…

基本的 Socket 模型

什么是Socket Socket 的中文名叫作插口&#xff0c;咋一看还挺迷惑的。事实上&#xff0c;双方要进行网络通信前&#xff0c;各自得创建一个 Socket&#xff0c;这相当于客户端和服务器都开了一个“口子”&#xff0c;双方读取和发送数据的时候&#xff0c;都通过这个“口子”…

机器学习 | 深入理解并掌握核心概念

在如今数字化时代的浪潮下&#xff0c;机器学习已经成为人工智能领域的璀璨明星。它像一面魔镜&#xff0c;赋予计算机系统学习和改进的能力&#xff0c;让机器能够从海量数据中提取规律、预测未来&#xff0c;甚至做出智能决策。本 专栏 将带您踏上机器学习的奇妙之旅&#xf…

什么是 Web3.0

什么是Web3.0 对于 Web3.0 的解释网上有很多&#xff0c;目前来说 Web3.0 是一个趋势&#xff0c;尚未有明确的定义。我们今天讨论下几个核心的点&#xff0c;就能很好的理解 Web3.0 要解决哪些问题 谁创造数据&#xff0c;这里的数据可以是一篇博客&#xff0c;一段视频&…

如何在容器内部进行抓包

//先获取POD 的容器ID号 //去pod容器所在节点进行解析id为pid号 //通过pid号进入这个容器的网络命名空间 docker inspect --format {{.State.Pid}} 05f38d2a61e29b5a9d24fc7a3906991ab92ecd58ff7e0eb4e339a4cc6b2c4fc4 //访问容器内部&#xff0c;Node01节点

微信小程序之WXSS模板样式、页面配置(.json)和网络数据请求

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

Flutter 自定义AppBar实现滚动渐变

1、使用ListView实现上下滚动。 2、使用Stack&#xff1a;允许将其子部件放在彼此的顶部&#xff0c;第一个子部件将放置在底部。所以AppBar&#xff0c;写在ListView下面。 3、MediaQuery.removePadding&#xff1a;当使用ListView的时候发现&#xff0c;顶部有块默认的Padd…

【 CSS 】定位

不要因为小小的失败而放弃大大的梦想&#xff0c;每一次坚持都是通向成功的一步。- 马克吐温 1. 定位 1.1 为何使用定位 我们先来看一个效果&#xff0c;同时思考一下用标准流或浮动能否实现类似的效果&#xff1f; 场景1: 某个元素可以自由的在一个盒子内移动位置&#xff0c…

企业如何高效营销?CBTC储能展助力企业市场拓展,黄金展位告急!

不论一家公司的规模有多大&#xff0c;展会都为之提供了一个很好的拓展业务的机会。参展是一种高效的营销方式。主要表现在哪些方面呢&#xff1f; 1、低成本接触合作客户。公司要接触到合格的客户&#xff0c;参加展会是最有效的方式。展会调查研究表明&#xff0c;通过销售电…

Effective C++——绝不在构造和析构构成中使用虚函数

父类的构造函数中调用的虚函数不是“虚”的 class father { public:virtual void log() {cout << "father building." << endl;}father(){log();} };class son : public father { public:virtual void log() {cout << "son building." &…

【面试突击】性能优化面试实战

&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308; 欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术的推送&#xff01; 在我后台回复…

【博士每天一篇论文-综述】Deep Echo State Network (DeepESN)_ A Brief Survey

阅读时间&#xff1a;2023-11-22 1 介绍 年份&#xff1a;2017 作者&#xff1a;C. Gallicchio 比萨大学计算机科学系终身教授助理教授&#xff0c;A. Micheli&#xff0c;比萨大学计算机科学系 期刊&#xff1a; ArXiv 引用量&#xff1a;68 这是两个大牛的论文&#xff0c;…

仓储管理系统——软件工程报告(需求分析)②

需求分析 一、系统概况 仓库管理系统是一种基于互联网对实际仓库的管理平台&#xff0c;旨在提供一个方便、快捷、安全的存取货物和查询商品信息平台。该系统通过在线用户登录查询&#xff0c;可以线上操作线下具体出/入库操作、查询仓库商品信息、提高仓库运作效率&#xff…

年货节电视盒子哪个好?内行分享权威网络电视盒子排行榜

淘宝、京东等已经开始了年货节促销&#xff0c;很多消费者买电视盒子会选择在此时入手&#xff0c;我近来收到了很多关于电视盒子哪个好的咨询&#xff0c;考虑到大家在选购时会参考排行榜&#xff0c;我这次要分享的是网络电视盒子排行榜&#xff0c;目前业内公认最好的电视盒…

LeetCode.2788. 按分隔符拆分字符串

题目 题目链接 分析 题目的意思是给我们一个字符串数组和一个分隔符&#xff0c;让我们按照分隔符把字符串数组分割成新的字符串数组。 看到这个描述&#xff0c;这不就是直接就是利用 按照分隔符分割字符串的系统库函数split()&#xff0c;这个函数的意思就是 把一个字符串…

C++(14.5)——再谈拷贝构造与深浅拷贝

上篇文章中&#xff0c;通过模拟的方式完成了类对象中常用的函数。在本篇文章中&#xff0c;将通过一个例子来进一步说明拷贝构造与深浅拷贝。 目录 1.再谈深浅拷贝与拷贝构造&#xff1a; 2. 流插入与流提取&#xff1a; 2.1 流插入&#xff1a; 2.2 流提取&#xff1a; …

性能优化-OpenCL运行时API介绍

「发表于知乎专栏《移动端算法优化》」 本文首先给出 OpenCL 运行时 API 的整体编程流程图&#xff0c;然后针对每一步介绍使用的运行时 API&#xff0c;讲解 API 参数&#xff0c;并给出编程运行实例。总结运行时 API 使用的注意事项。最后展示基于 OpenCL 的图像转置代码。在…

matlab模型变量一般说明,标定和显示量,以及产生a2l文件,自动填充a2l地址,并使用标定工具ati进行标定(推荐重要)

注意我是用的是matlab2019b 1&#xff0c;输入标定量&#xff0c;使用constant&#xff0c;用cal函数包裹 2&#xff0c;输出显示量&#xff0c;在划线上标注&#xff0c;然后用display函数包裹&#xff0c; 第一步和第二步完成以后&#xff0c;生产标定量a2l 3&#xff0c;输入…

分类预测 | Matlab实现LSTM-Attention-Adaboost基于长短期记忆网络融合注意力机制的Adaboost数据分类预测/故障识别

分类预测 | Matlab实现LSTM-Attention-Adaboost基于长短期记忆网络融合注意力机制的Adaboost数据分类预测/故障识别 目录 分类预测 | Matlab实现LSTM-Attention-Adaboost基于长短期记忆网络融合注意力机制的Adaboost数据分类预测/故障识别分类效果基本描述程序设计参考资料 分类…