网络编程作业之完整版通讯系统(上)

由于篇幅过长,完整版代码分为上下两篇文章

本篇文章主要是展示服务端的所有代码😊

相比韩顺平老师的服务端代码,我新增了以下几个内容
  • 对用户的登录进行了检查,判断是否重复登录或者出现账号不存在的问题。如果登陆失败会返回失败的消息类型给客户端。
  • 对于用户发送的消息对象,如果对象不存在就会返回发送消息失败的消息类型给客户端。发送文件也加了这条限制。
  • 在最后的离线发送消息扩展也已经完成,并且保证用户能够收到多条离线信息。
  • 新增了注册账号的功能。
  • 新增了退出账号的功能。

公共模块的代码在下篇文章中,由于代码量太多,所以本篇不过多赘述

下面开始展示我的代码模块已经各个模块介绍🚚


客户端代码图示🏡

在这里插入图片描述

客户端代码

公共部分在下篇文中中显示 -> common
—————

服务部分内容-> service

Service_User二级系统用户模块🍧

package com.all.qqclient.service;


import com.all.qqclient.utils.readOperate;
import com.all.qqcommon.Message;
import com.all.qqcommon.MessageType;
import com.all.qqcommon.User;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 捶捶自己
 * @version: 1.0
 * @Date: 2022/07/04/15:00
 * @Description: 用于二级用户系统模块服务
 */
public class Service_User {
    // -- 这个user对象是从User中拉取过来的登录对象
    User user = Service_System.loginUser;

    // -- 获取在线用户列表
    public void getOnlineFriendList() {
        // -- 想要获取已经登陆到系统的用户信息
        Message message = new Message();
        message.setSender(user.getUserId());
        message.setMessageType(MessageType.MESSAGE_GET_ONLINE_FRIEND);
        // -- 1. 先调用线程集合,然后通过用户Id获取到对应的线程
        // -- 2. 再通过对应的线程获取到socket,利用socket获取到输出流
        // -- 3. 将输出流赋给输出流对象,对消息进行输出
        try {
            ClientConnectServerThread clientConnectServerThread = ManageClientConnectServerThread.byUserIdGetThread(user.getUserId());
            Socket socket = clientConnectServerThread.getSocket();
            OutputStream outputStream = socket.getOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(outputStream);
            oos.writeObject(message);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // -- 用户对系统进行的反馈
    public void sendUserFeedback() {
        System.out.print("♥♥请输入想要反馈的内容: ");
        String feedBack = readOperate.readString(200);
        // -- 想要获取已经登陆到系统的用户信息
        Message message = new Message();
        message.setContent(feedBack);
        message.setSender(user.getUserId());
        message.setMessageType(MessageType.MESSAGE_GET_FEED_BACK);
        // -- 1. 先调用线程集合,然后通过用户Id获取到对应的线程
        // -- 2. 再通过对应的线程获取到socket,利用socket获取到输出流
        // -- 3. 将输出流赋给输出流对象,对消息进行输出
        try {
            ObjectOutputStream oos
                    = new ObjectOutputStream(ManageClientConnectServerThread.byUserIdGetThread(user.getUserId()).getSocket().getOutputStream());
            oos.writeObject(message);
            System.out.println("o(* ̄▽ ̄*)ブ已经向服务器反馈成功!请耐心等待!");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // -- 退出登录账号
    public boolean outLookLoginAccount() {
        boolean outLook = readOperate.readOutLookConfirm(false);
        if (outLook) {
            // -- 向服务器发送用户退出账号的消息
            Message message = new Message();
            message.setSender(user.getUserId());
            message.setMessageType(MessageType.MESSAGE_LOGIN_EXIST);
            // -- 1. 先调用线程集合,然后通过用户Id获取到对应的线程
            // -- 2. 再通过对应的线程获取到socket,利用socket获取到输出流
            // -- 3. 将输出流赋给输出流对象,对消息进行输出
            try {
                Socket socket = ManageClientConnectServerThread.byUserIdGetThread(user.getUserId()).getSocket();
                ObjectOutputStream oos
                        = new ObjectOutputStream(socket.getOutputStream());
                oos.writeObject(message);
                Thread.sleep(50);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        return outLook;
    }

    // -- 发送用户退出系统的消息
    public boolean sendUserExitSystemMessage() {
        boolean loop = readOperate.readExitConfirm(true);
        if (!loop) {
            // -- 向服务器发送用户退出系统的消息
            Message message = new Message();
            message.setSender(user.getUserId());
            message.setMessageType(MessageType.MESSAGE_CLIENT_EXIT);
            // -- 1. 先调用线程集合,然后通过用户Id获取到对应的线程
            // -- 2. 再通过对应的线程获取到socket,利用socket获取到输出流
            // -- 3. 将输出流赋给输出流对象,对消息进行输出
            try {
                ObjectOutputStream oos
                        = new ObjectOutputStream(ManageClientConnectServerThread.byUserIdGetThread(user.getUserId()).getSocket().getOutputStream());
                oos.writeObject(message);
                System.exit(0);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        return loop;
    }

}


Service_System一级系统模块🍧

package com.all.qqclient.service;

import com.all.qqclient.utils.readOperate;
import com.all.qqcommon.Message;
import com.all.qqcommon.MessageType;
import com.all.qqcommon.User;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 捶捶自己
 * @version: 1.0
 * @Date: 2022/07/07/8:22
 * @Description: 处理一级系统服务模块问题
 */
public class Service_System {
    User user = new User();
    static User loginUser = new User();
    private Socket socket;

    // -- 检查登陆账号的信息
    public boolean checkLoginUserInfo(String userId, String password) {
        boolean isSucceed = false;
        user.setUserId(userId);
        user.setPassword(password);
        user.setRegister(false);
        // -- 存储登录信息
        loginUser.setUserId(userId);
        loginUser.setPassword(password);
        try {
            socket = new Socket(InetAddress.getByName("127.0.0.1"), 4399);
            // -- 向服务端发送用户信息
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject(user);
            // -- 接收服务端的信息
            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
            Message message = (Message) ois.readObject();

            // -- 判断是否登录成功
            if (message.getMessageType().equals(MessageType.MESSAGE_RET_USER_LOGIN_STATE)) {
                // -- 用户已经存在,无法继续登录
                System.out.println("\n💔用户" + userId + "已经存在,无法重复登录");
                // -- 如果登录失败,线程不会创建成功,因此要关闭socket, 避免资源浪费
                oos.close();
                ois.close();
                socket.close();
            } else if (message.getMessageType().equals(MessageType.MESSAGE_LOGIN_SUCCEED)) {
                // -- 如果登录成功就启动客户端线程,等待消息的发送
                ClientConnectServerThread clientConnectServerThread = new ClientConnectServerThread(socket);
                clientConnectServerThread.start();

                // -- 为了后方的扩展,可以将线程放入集合中管理
                ManageClientConnectServerThread.addClientConnectServerThread(userId, clientConnectServerThread);
                // -- 避免发生错误,将登录确认放在线程之后
                isSucceed = true;
            } else {
                oos.close();
                ois.close();
                socket.close();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return isSucceed;
    }

    // -- 创建新的登录账号
    public void registerUserAccount() {
        int count = 3;
        System.out.print("♥请输入您想要创建的用户名: ");
        String inputUserId = readOperate.readString(10);
        System.out.print("♥请输入您创建的用户名密码: ");
        String inputPassword = readOperate.readString(200, "");
        while (true) {
            System.out.print("♥请再次输入您创建的用户名密码: ");
            String confirmPassword = readOperate.readString(200, "");
            if (confirmPassword.equals(inputPassword)) {
                break;
            }
            count--;
            if (count != 0) {
                System.out.println("💔您输入的密码与上次不符, 请确认之后在进行输入哦!");
            } else {
                System.out.println("💔您已经连续输入失败三次,注册用户失败/(ㄒoㄒ)/~~");
                return;
            }
        }
        user.setUserId(inputUserId);
        user.setPassword(inputPassword);
        user.setRegister(true);

        try {
            socket = new Socket(InetAddress.getByName("127.0.0.1"), 4399);
            // -- 向服务端发送用户信息
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject(user);
            // -- 接收服务端的信息
            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
            Message message = (Message) ois.readObject();
            if (message.getMessageType().equals(MessageType.MESSAGE_RET_REGISTER_SUCCEED)) {
                System.out.println("♥用户创建成功!*★,°*:.☆( ̄▽ ̄)/$:*.°★* 。\n" + "🖊新账号用户名为: "
                        + message.getSender() + "\t新账号密码为: " + message.getContent()
                        + "\n🖊新账号创建时间为: " + message.getSendTime()
                        + "\n❀❀❀系统小助手提示您要请牢记用户名和密码哦!祝您每一天都开心愉快!\n");
                oos.close();
                ois.close();
                socket.close();
                return;
            }
            // -- 既然消息类型都加上去了,只用一个else也太可惜了[doge]!
            if (message.getMessageType().equals(MessageType.MESSAGE_RET_REGISTER_FAIL)) {
                System.out.println("💔用户创建失败!/(ㄒoㄒ)/~~\n" + "(;′⌒`)失败原因为: "
                        + message.getContent() + "\n🖊新账号创建失败时间为: " + message.getSendTime()
                        + "\n❀❀❀系统小助手提示您可以再次尝试创建哦!祝您每一天都开心愉快!\n");
                oos.close();
                ois.close();
                socket.close();
                return;
            }
            // TODO 等待新的系统功能 demo: 系统反馈功能
            if (message.getMessageType().equals("")) {
                System.out.println("等待扩展");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}


MessageClientToServer客户端发送消息模块🍧

package com.all.qqclient.service;

import com.all.qqclient.utils.readOperate;
import com.all.qqcommon.Message;
import com.all.qqcommon.MessageType;

import java.io.IOException;
import java.io.ObjectOutputStream;


/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 捶捶自己
 * @version: 1.0
 * @Date: 2022/07/05/20:27
 * @Description: 消息发送模块
 */
public class MessageClientToServer {


    public void sendMessageToAll(String senderId) {
        System.out.print("♥♥请输入您想要发送的消息: ");
        String content = readOperate.readString(200);
        // -- 对消息进行封装
        Message message = new Message();
        message.setMessageType(MessageType.MESSAGE_COMM_MES_TO_ALL);
        message.setSender(senderId);
        message.setContent(content);
        message.setSendTime(message.getSendMessageNowTime());
        // -- 将信息发送给服务器
        try {
            ObjectOutputStream oos
                    = new ObjectOutputStream(ManageClientConnectServerThread.byUserIdGetThread(senderId).getSocket().getOutputStream());
            oos.writeObject(message);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public void sendMessageToOne(String senderId) {
        System.out.print("♥♥请输入您想要发送消息的用户: ");
        String getterId = readOperate.readString(10);
        System.out.print("♥♥请输入您想要发送的消息: ");
        String content = readOperate.readString(200);
        // -- 对消息进行封装
        Message message = new Message();
        message.setMessageType(MessageType.MESSAGE_COMM_MES);
        message.setSender(senderId);
        message.setContent(content);
        message.setGetter(getterId);
        message.setSendTime(message.getSendMessageNowTime());
        // -- 将信息发送给服务器
        try {
            ObjectOutputStream oos
                    = new ObjectOutputStream(ManageClientConnectServerThread.byUserIdGetThread(senderId).getSocket().getOutputStream());
            oos.writeObject(message);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}


ManageClientConnectServerThread管理客户端账户开启的线程🍧

package com.all.qqclient.service;

import java.util.HashMap;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 捶捶自己
 * @version: 1.0
 * @Date: 2022/07/04/15:43
 * @Description: 采用集合管理客户端连接到服务器的线程
 */
public class ManageClientConnectServerThread {
    // -- 把多线程放入hashMap集合中 string 表示 id, value 表示线程
    private static HashMap<String, ClientConnectServerThread> hm = new HashMap<>();

    // -- 将线程加入到集合中去
    public static void addClientConnectServerThread(String userId, ClientConnectServerThread clientConnectServerThread) {
        hm.put(userId, clientConnectServerThread);
    }
    // -- 通过userId得到对应的线程
    public static ClientConnectServerThread byUserIdGetThread(String userId) {
        return hm.get(userId);
    }
}


ClientTransmissionFileService客户端发送文件模块🍧

package com.all.qqclient.service;

import com.all.qqclient.utils.readOperate;
import com.all.qqcommon.Message;
import com.all.qqcommon.MessageType;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 捶捶自己
 * @version: 1.0
 * @Date: 2022/07/06/15:40
 * @Description: 客户端传输文件服务
 */
public class ClientTransmissionFileService {

    public void sendFileToOne(String senderId) {
        // -- 控制台输入文件地址
        System.out.print("♥♥请输入您想要发送消息的用户: ");
        String getterId = readOperate.readString(10);
        System.out.print("♥♥请输入您想要发送的文件地址: ");
        // -- 文件路径需要改为自己的实际路径
        String fileFromPath = readOperate.readString(200, "C:\\Users\\18446\\Desktop\\beautiful.png");
        System.out.print("♥♥请输入您想要发送到的目标文件地址: ");
        // -- 文件路径需要改为自己的实际路径
        String fileToPath = readOperate.readString(200, "C:\\Users\\18446\\Desktop\\Girl.png");

        // -- 文件消息封装
        Message message = new Message();
        message.setMessageType(MessageType.MESSAGE_FILE_MES);
        message.setSendTime(message.getSendMessageNowTime());
        message.setFileFromPath(fileFromPath);
        message.setFileToPath(fileToPath);
        message.setSender(senderId);
        message.setGetter(getterId);

        // -- 将文件内容进行读取并转为字节流
        FileInputStream fileInputStream = null;
        byte[] fileBytes = new byte[(int) new File(fileFromPath).length()];
        try {
            fileInputStream = new FileInputStream(fileFromPath);
            fileInputStream.read(fileBytes);
            // -- 将文件内容转为字节流发送
            message.setFileData(fileBytes);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        // -- 提示信息
        System.out.println("\n用户" + senderId + "给"
                + getterId + "发送了一个信息从" + fileFromPath + "到" + fileToPath + "路径中, 请查收");

        // -- 发送信息报
        try {
            ObjectOutputStream oos
                    = new ObjectOutputStream(ManageClientConnectServerThread.byUserIdGetThread(senderId).getSocket().getOutputStream());
            oos.writeObject(message);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

ClientConnectServerThread用户登录线程开启模块🍧

package com.all.qqclient.service;

import com.all.qqcommon.Message;
import com.all.qqcommon.MessageType;

import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.net.Socket;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 捶捶自己
 * @version: 1.0
 * @Date: 2022/07/04/15:28
 * @Description: 客户端连接线程创建
 */
public class ClientConnectServerThread extends Thread {
    // -- 该线程必须持有socket
    private Socket socket;

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

    // -- 为了更方便的获取socket
    public Socket getSocket() {
        return socket;
    }

    public void setSocket(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        boolean lock = true;
        while (lock) {
            try {
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                Message message = (Message) ois.readObject();
                // -- 通过判断客户端发来的信息,进行信息的分块处理
                switch (message.getMessageType()) {
                    case MessageType.MESSAGE_RET_ONLINE_FRIEND:
                        // -- 通过将用户信息分割为几部分进行输出
                        String[] Info = message.getContent().split(" ");
                        System.out.println("\n=======★★当前在线的用户列表★★=======\n" +
                                "♥♥当前共有" + Info.length + "名用户同时在线");
                        for (int i = 0; i < Info.length; i++) {
                            System.out.println("♥♥用户" + (i < 9 ? ("0" + (i + 1)) : (i + 1)) + ": " + Info[i]);
                        }
                        System.out.print("\n♥♥请输入您的选择: ");
                        break;
                    case MessageType.MESSAGE_COMM_MES:
                        System.out.print("\n用户" + message.getSender() + "给你发来了一个消息🐟🐟🐟🐟\n"
                                + "🆒消息内容为: " + message.getContent() + "\n🆒发送时间为: "
                                + message.getSendTime() + "\n♥♥请输入你的选择: ");
                        break;
                    case MessageType.MESSAGE_COMM_MES_FAIL:
                        System.out.print("\n用户" + message.getSender() + "消息发送失败🐟🐟🐟🐟" + "\n🆒原因是: "
                                + message.getContent() + "\n🆒消息发送失败时间为: " + message.getSendTime()
                                + "\n♥♥请输入你的选择: ");
                        break;
                    case MessageType.MESSAGE_COMM_MES_TO_ALL:
                        System.out.print("\n用户" + message.getSender() + "给全体成员发来了一个消息🐟🐟🐟🐟\n"
                                + "🆒消息内容为: " + message.getContent() + "\n🆒发送时间为: "
                                + message.getSendTime() + "\n♥♥请输入你的选择: ");
                        break;
                    case MessageType.MESSAGE_FILE_MES:
                        System.out.print("\n用户" + message.getSender() + "给你发来了一个文件🐟🐟🐟🐟\n"
                                + "📕文件存放路径为: " + message.getFileToPath() + "\n📕发送时间为: "
                                + message.getSendTime());
//                        System.out.print("\n📕检查路径是否正确,如果正确可以直接回车,如果错误请进行填写: ");
//                        String getterPointerFilePath = new Scanner(System.in).next();
//                        if (getterPointerFilePath.equals("")) {
//                            getterPointerFilePath += message.getFileToPath();
//                        }
                        message.setFileToPath(message.getFileToPath());
                        // -- 将文件传入到指定路径中去
                        FileOutputStream fileOutputStream = new FileOutputStream(message.getFileToPath());
                        fileOutputStream.write(message.getFileData());
                        fileOutputStream.close();
                        System.out.print("\n♥♥请输入你的选择: ");
                        break;
                    case MessageType.MESSAGE_FILE_MES_FAIL:
                        System.out.print("\n用户" + message.getSender() + "文件发送失败🐟🐟🐟🐟" + "\n(#`O′)原因是: "
                                + message.getContent() + "\n文件发送失败时间为: " + message.getSendTime()
                                + "\n♥♥请输入你的选择: ");
                        break;
                    case MessageType.MESSAGE_LOGIN_EXIST:
                        System.out.println("\no(* ̄▽ ̄*)ブ用户" + message.getSender() + "已经退出登录");
                        ois.close();
                        socket.close();
                        lock = false;
                        break;
                    default:
                        System.out.println("其他消息暂时不处理");
                        break;
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}


主题显示部分内容-> view

view客户端主题显示区域🍧

package com.all.qqclient.view;


import com.all.qqclient.service.ClientTransmissionFileService;
import com.all.qqclient.service.MessageClientToServer;
import com.all.qqclient.service.Service_System;
import com.all.qqclient.service.Service_User;
import com.all.qqclient.utils.readOperate;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 捶捶自己
 * @version: 1.0
 * @Date: 2022/07/03/20:47
 * @Description: QQ客户端界面
 */
@SuppressWarnings({"all"})
public class View {
    private boolean loop = true;
    private boolean outLook = false;
    private Service_System service_system = new Service_System(); // -- 用于一级系统模块服务
    private Service_User service_user = new Service_User();// -- 用于二级用户系统模块服务
    private MessageClientToServer messageClientToServer = new MessageClientToServer();// -- 用于消息的发送
    private ClientTransmissionFileService clientTransmissionFileService = new ClientTransmissionFileService();// -- 用于文件的传输

    private void mainMenu() {
        while (loop) {
            System.out.println("==============★欢迎登录网络通讯系统★==============\n" +
                    "\t\t1. 登录系统♥\n" + "\t\t2. 注册账号♥\n" + "\t\t9. 退出系统♥");
            System.out.print("👉请输入你的选择: ");
            String key = readOperate.readString(1);
            switch (key) {
                case "1":
                    outLook = false;
                    System.out.print("♥请输入您的用户名: ");
                    String userId = readOperate.readString(10);
                    System.out.print("♥请输入您的密码: ");
                    String accountPassword = readOperate.readString(16);
                    if (service_system.checkLoginUserInfo(userId, accountPassword)) {
                        System.out.println("==============⭐⭐⭐欢迎 (用户" + userId + ") " + "登录成功⭐⭐⭐==============");
                        // -- 进入二级系统
                        while (!outLook) {
                            System.out.println("\n=======★★网络通讯系统二级菜单 (用户" + userId + ") ★★=======\n" +
                                    "\t\t1. 显示用户在线列表♥♥\n" + "\t\t2. 群发消息♥♥\n" + "\t\t3. 私聊消息♥♥\n" +
                                    "\t\t4. 发送文件♥♥\n" + "\t\t5. 系统反馈♥♥\n" + "\t\t8. 退出当前登陆账号♥♥\n" + "\t\t9. 退出系统♥♥");
                            System.out.print("♥♥请输入你的选择:");
                            key = readOperate.readString(1);
                            switch (key) {
                                case "1":
                                    service_user.getOnlineFriendList();
                                    break;
                                case "2":
                                    messageClientToServer.sendMessageToAll(userId);
                                    break;
                                case "3":
                                    messageClientToServer.sendMessageToOne(userId);
                                    break;
                                case "4":
                                    clientTransmissionFileService.sendFileToOne(userId);
                                    break;
                                case "5":
                                    service_user.sendUserFeedback();
                                    break;
                                case "8":
                                    outLook = service_user.outLookLoginAccount();// -- true 表示退出
                                    break;
                                case "9":
                                    loop = service_user.sendUserExitSystemMessage();// -- false 表示退出
                                    outLook = loop;
                                    break;
                            }
                        }
                    } else {
                        System.out.println("💔登录失败,请再次尝试登录~~~\n");
                    }
                    break;
                case "2":
                    service_system.registerUserAccount();
                    break;
                case "9":
                    loop = readOperate.readExitConfirm(loop);
                    break;
            }
        }
    }

    public static void Run() {
        new View().mainMenu();
    }
}


客户端主程序入口-> main

Main客户端入口🍧

package com.all.qqclient.main;

import com.all.qqclient.view.View;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 捶捶自己
 * @version: 1.0
 * @Date: 2022/07/07/9:52
 * @Description: 客户端主程序入口
 */
public class Main {
    public static void main(String[] args) {
        View.Run();
    }
}


附上客户端也就是下篇的链接-> 点击跳转

小总结:添加了许多自己的元素,虽然很累,经常爆红,但是还是很开心能够完成,下面展示一下部分功能效果。

注册功能

在这里插入图片描述

登录功能

在这里插入图片描述

显示在线人数和在线列表以及离线私聊功能

在这里插入图片描述
在这里插入图片描述

服务器反馈功能

在这里插入图片描述
在这里插入图片描述

退出登录功能
在这里插入图片描述

退出系统功能

在这里插入图片描述

登录检测功能

在这里插入图片描述
在这里插入图片描述

群聊功能

在这里插入图片描述

服务端发送新闻以及关闭功能

在这里插入图片描述
在这里插入图片描述

发送文件功能

在这里插入图片描述
在这里插入图片描述

所拥有的一切实力,都是用坚持不懈的毅力与奋斗换来的。没有人天生就会,加油加油加油!

再次给出下篇链接-> 点击跳转

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

捶捶自己

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值