2021-08-13 Java练习题

通信软件的功能:有客户端和服务器端,实现客户端和服务器相互不停的发送和接收消息。要求发送和接收消息可以同时进行。

一、客户端与服务器交流

服务器
package zpb.practice;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Scanner;

/**
 * @author Peter Cheung
 * @user PerCheung
 * @date 2021/8/14 23:00
 * <p>
 * 通信软件的功能
 * 有客户端和服务器端,实现客户端和服务器相互不停的发送和接收消息。
 * 要求发送和接收消息可以同时进行。
 */
public class ServerTOClient extends Thread {
    ServerSocket server = null;
    Socket socket = null;

    public ServerTOClient(int port) {
        try {
            server = new ServerSocket(port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //函数入口
    public static void main(String[] args) {
        ServerTOClient server = new ServerTOClient(8888);
        server.start();
    }

    @Override
    public void run() {

        super.run();
        try {
            System.out.println("等待连接...");
            socket = server.accept();
            new sendMessThread().start();//连接并返回socket后,再启用发送消息线程
            System.out.println(socket.getInetAddress().getHostAddress() + "连接成功!");
            InputStream in = socket.getInputStream();
            int len = 0;
            byte[] buf = new byte[64];
            try {
                while ((len = in.read(buf)) != -1) {
                    System.out.println("客户端:" + new String(buf, 0, len));
                }
            } catch (SocketException s) {
                System.out.println("服务器已关闭");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    class sendMessThread extends Thread {
        @Override
        public void run() {
            super.run();
            Scanner scanner = null;
            OutputStream out = null;
            try {
                if (socket != null) {
                    scanner = new Scanner(System.in);
                    out = socket.getOutputStream();
                    String in = "";
                    while (!in.equals("关闭")) {
                        in = scanner.next();
                        out.write(("服务器:" + in).getBytes());
                        out.flush();//清空缓存区的内容
                    }
                    scanner.close();
                    out.close();
                    socket.close();
                }
            } catch (IOException e) {
                System.out.println("客户端已关闭,你的信息无法传输了");
            }
        }
    }
}
客户端
package zpb.practice;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.util.Scanner;

/**
 * @author Peter Cheung
 * @user PerCheung
 * @date 2021/8/14 23:05
 * <p>
 * 通信软件的功能
 * 有客户端和服务器端,实现客户端和服务器相互不停的发送和接收消息。
 * 要求发送和接收消息可以同时进行。
 */
public class ClientTOServer extends Thread {

    //定义一个Socket对象
    Socket socket = null;

    public ClientTOServer(String host, int port) {
        try {
            //需要服务器的IP地址和端口号,才能获得正确的Socket对象
            socket = new Socket(host, port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //函数入口
    public static void main(String[] args) {
        //需要服务器的正确的IP地址和端口号
        ClientTOServer clientTest = new ClientTOServer("127.0.0.1", 8888);
        clientTest.start();
    }

    @Override
    public void run() {
        //客户端一连接就可以写数据个服务器了
        new sendMessThread().start();
        super.run();
        try {
            // 读Sock里面的数据
            InputStream s = socket.getInputStream();
            byte[] buf = new byte[64];
            int len = 0;
            try {
                while ((len = s.read(buf)) != -1) {
                    System.out.println(new String(buf, 0, len));
                }
            } catch (SocketException so) {
                System.out.println("客户端已关闭");
            }

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

    //往Socket里面写数据,需要新开一个线程
    class sendMessThread extends Thread {
        @Override
        public void run() {
            super.run();
            //写操作
            Scanner scanner = null;
            OutputStream os = null;
            try {
                scanner = new Scanner(System.in);
                os = socket.getOutputStream();
                String in = "";
                while (!in.equals("再见")) {
                    in = scanner.next();
                    os.write(("" + in).getBytes());
                    os.flush();
                }
            } catch (IOException e) {
                System.out.println("服务器已关闭,你的信息无法传输了");
            }
            scanner.close();
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

代码的实现参考自此博客,十分感谢!

二、多个客户端与服务器群流

服务器
package zpb.practice;

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

/**
 * @author Peter Cheung
 * @user PerCheung
 * @date 2021/8/14 22:00
 *
 * 通信软件的功能
 * 有客户端和服务器端,实现客户端和服务器相互不停的发送和接收消息。
 * 要求发送和接收消息可以同时进行。
 */
public class ChatServer {
    private static final int port = 8888;
    private ServerSocket server_socket;
    //存放所有访问服务器的客户端和其用户名
    private Map<String, Socket> clients;

    public ChatServer() throws IOException {
        this.server_socket = new ServerSocket(port);
        this.clients = new HashMap<>();

        while (true) {
            //accept方法一直阻塞直到接收到一个客户端的请求 并返回该客户端的套接字socket
            Socket client_socket = server_socket.accept();
            //开启新线程处理客户端的请求
            new HandleClientThread(client_socket).start();
        }
    }

    public static void main(String[] args) throws IOException {
        new ChatServer();
    }

    //显示所有用户列表
    private synchronized void showUserList() {
        System.out.println("🐉🐉🐉🐉🐉用户列表🐉🐉🐉🐉🐉");
        System.out.println("当前在线人数:" + clients.size());
        for (Map.Entry<String, Socket> user : clients.entrySet()) {
            System.out.println(user.getKey());
        }
    }

    //广播消息message给所有客户端
    private synchronized void sendToAllClient(String message) {
        try {
            //获取所有客户端套接字socket的输出流
            for (Map.Entry<String, Socket> user : clients.entrySet()) {
                PrintWriter server_out = new PrintWriter(user.getValue().getOutputStream(), true);
                server_out.println(message);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //转发消息给某个特定的客户端
    private synchronized void sendToUser(String sendUser, String receiveUser, String message) {
        try {
            PrintWriter out = new PrintWriter(clients.get(receiveUser).getOutputStream(), true);
            out.println(sendUser + "对你说:" + message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //某个客户端退出服务器
    private synchronized void offline(String username) {
        clients.remove(username);
        if (username != null) {
            sendToAllClient(username + "已下线!");
        }
        ChatServer.this.showUserList();
    }

    //启用一个线程处理一个客户端的请求
    private class HandleClientThread extends Thread implements Runnable {
        private Socket client_socket;
        private BufferedReader server_in;
        private PrintWriter server_out;
        private String client_name;

        public HandleClientThread(Socket client_socket) throws IOException {
            this.client_socket = client_socket;
            server_in = new BufferedReader(new InputStreamReader(this.client_socket.getInputStream()));
            server_out = new PrintWriter(this.client_socket.getOutputStream(), true);
            //通知客户端输入用户名
            server_out.println("您已连接上聊天服务器!请输入用户名:");
        }

        //处理客户端消息
        @Override
        public void run() {
            //判断该客户端是否第一次访问
            int flag = 0;
            String fromClientData;

            //循环接收该客户端发送的数据
            try {
                while ((fromClientData = server_in.readLine()) != null) {
                    //该客户端请求关闭服务器的连接
                    if ("退出聊天".equals(fromClientData)) {
                        ChatServer.this.offline(this.client_name);
                        break;
                    }

                    //判断该客户端是否第一次访问
                    if (flag++ == 0) {
                        this.client_name = fromClientData;
                        clients.put(this.client_name, this.client_socket);
                        sendToAllClient("欢迎" + this.client_name + "进入聊天室");
                        ChatServer.this.showUserList();
                        continue;
                    }

                    //处理私聊 格式 @接收客户端的名字:对其说的话
                    if (fromClientData.startsWith("@")) {
                        String receiveName = fromClientData.substring(1, fromClientData.indexOf(":"));
                        String message = fromClientData.substring(fromClientData.indexOf(":") + 1, fromClientData.length());
                        sendToUser(this.client_name, receiveName, message);
                    } else {
                        //处理群发
                        sendToAllClient(this.client_name + "说:" + fromClientData);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
客户端
package zpb.practice;

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

/**
 * @author Peter Cheung
 * @user PerCheung
 * @date 2021/8/14 22:39
 * <p>
 * 通信软件的功能
 * 有客户端和服务器端,实现客户端和服务器相互不停的发送和接收消息。
 * 要求发送和接收消息可以同时进行。
 */
public class ChatClient {
    private static final int port = 8888;
    private static final String ip_adress = "127.0.0.1";
    //发送消息给服务器的输出流
    private PrintWriter client_out;
    //接收服务器消息的输入流
    private BufferedReader client_in;
    //客户端套接字
    private Socket client_socket;
    public ChatClient() throws IOException {
        //提供ip和端口
        client_socket = new Socket(ip_adress, port);
        client_in = new BufferedReader(new InputStreamReader(client_socket.getInputStream()));
        client_out = new PrintWriter(client_socket.getOutputStream(), true);

        //开启新线程处理监听服务器端发来的消息
        new ClientThread().start();

        //客户端循环发送群聊,私聊消息
        while (true) {
            //获取客户端的输入
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String input = br.readLine();
            //发送消息给服务器
            client_out.println(input);

            //客户端退出服务器
            if (input.equals("退出聊天")) {
                client_out.close();
                client_in.close();
                client_socket.close();
                System.exit(886);
            }
        }
    }

    public static void main(String[] args) throws IOException {
        new ChatClient();
    }

    //监听服务器端发来的消息
    private class ClientThread extends Thread implements Runnable {
        @Override
        public void run() {
            try {
                //接收服务器消息
                String fromServer_data;
                while ((fromServer_data = client_in.readLine()) != null) {
                    System.out.println(fromServer_data);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

代码的实现参考自此博客,十分感谢!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PerCheung

觉得有帮助的话就打赏支持一下吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值