栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Socket网络程序设计:模拟QQ聊天室

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Socket网络程序设计:模拟QQ聊天室

多线程基础,实现群聊系统

Java实验1-7完整实验报告

一、实验题目

采用多线程技术实现一个服务器端和多个客户端之间的聊天功能。

二、设计思路
(1)总体设计:设计一个服务端线程,设计服务端的功能。设计一个服务端,等待客户端连接,启动服务端线程。设计一个客户端线程,客户端线程定义客户端的功能。设计一个客户端,用于启动客户端线程。
(2)功能实现;客户端发送消息给服务端,由服务端转发为其他客户端,实现群聊功能
(3)服务端线程设计:这个线程里设计了服务端读取客户端信息,并转发给其他客户端,向客户端发送上线下线提示
(4)服务端设计:服务端与客户端建立连接,然后启动服务端线程
(5)客户端线程设计:包括读取控制台信息,向服务端发送信息,当客户端输入bye,客户端线下
(6)客户端设计:客户端启动客户端线程
三、程序代码

客户端

package Test06.test2.Demo02;

import java.io.IOException;

public class Client {
    public static void main(String[] args) throws IOException {

        new ClientThread().chat();
    }
}

客户端线程

package Test06.test2.Demo02;

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

public class ClientThread {

    private final Socket client;

    private final PrintWriter pw;

    private BufferedReader br;
    private Scanner sc = new Scanner(System.in);
    private boolean isRunning = true;

    // 构造方法
    public ClientThread() throws IOException {
        // 家里连接指定要连接到的主机IP+端口号
        client = new Socket("localhost", 8888);
        // 输出流
        pw = new PrintWriter(client.getOutputStream(), true);
        // 输入流

        br = new BufferedReader(new InputStreamReader(client.getInputStream()));
    }

    
    public void chat() {

        //用户名设置,给线程一个区分
        System.out.println("请输入您的用户名");
        String username = sc.next();//直接这么写,显示s
        pw.println(username);
        //提示可以开始聊天
        System.out.println("***********欢迎来到聊天室***********");

        //开启接收信息的线程
        Thread receiveMsg = new Thread(new ReceiveThread());
        receiveMsg.start();

        // 多次发送
        while (true) {
            // 获取要发送的信息
            String sendMsg= sc.next();
            // 将信息发送到服务器
            pw.println(sendMsg);
            // 当发送bye时,结束循环
            if (sendMsg.equals("bye")) {
                isRunning = false;
                receiveMsg.stop();
                break;
            }
        }
        // 关闭资源
        release();
    }


    
    private void release() {
        if (sc != null) {
            sc.close();
        }
        if (client != null) {
            try {
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (br != null) {
                    try {
                        br.close();
                    } catch (IOException e) {

                        e.printStackTrace();
                    } finally {
                        if (pw != null) {
                            pw.close();
                        }
                    }
                }
            }
        }
    }

    
    class ReceiveThread implements Runnable {
        @Override
        public void run() {
            //接收信息
            while (isRunning) {
                String receivedMsg;
                try {

                    receivedMsg = br.readLine();
                    System.out.println(receivedMsg);
                } catch (IOException e) {

                    e.printStackTrace();
                }
            }
        }
    }
}

服务端

package Test06.test2.Demo02;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class Server {

    //容器,用来存放所有连接的客户对应的处理实例
    public static List list = new CopyOnWriteArrayList<>();
    

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = null;


        // 1.创建服务器套接字,指定监听端口
        serverSocket = new ServerSocket(8888);

        // 无限次循环监听
        while (true) {
            // 2.阻塞式监听
            Socket server = serverSocket.accept();
            System.out.println("一个客户建立了连接");
            //OnlineNum++;
            // 3.创建线程服务于该用户
            new Thread(new ServerThread(server)).start();
           // System.out.println("当前系统有"+list.size());
            //if(onlineNum==0){
                //break;
            //}
            //System.out.println(OnlineNum);
            //if(OnlineNum1==0){
            //    break;
            //}

        }

    }
}

服务端线程

package Test06.test2.Demo02;//服务器端用到的类,实现Runnable接口

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

public class ServerThread implements Runnable {
    private Socket server = null;

    private BufferedReader br = null;

    private PrintWriter pw = null;
    private String username = null;            //该实例服务的用户的名字
   // private boolean isRunning = true;        //服务结束的标志

    //构造方法
    public ServerThread(Socket server) throws IOException{
        this.server = server;
        //通过Socket实例构造输入输出流
        this.br = new BufferedReader(new InputStreamReader(server.getInputStream()));
        this.pw = new PrintWriter(server.getOutputStream(), true);
    }


    @Override
    public void run() {

        //将该线程加入list集合
        Server.list.add(this);

        //获取该用户的姓名
        String username = receiveMsg();
        this.username = username;
        //Server.OnlineNum1++;
        //System.out.println("OnlineNum1"+Server.OnlineNum1);
        //发送系统欢迎信息
        sendSystemMsg(this.username + " 加入了聊天室");
        //多次接收与发送
        while (true) {
            //接收信息
            String msg = receiveMsg();

            //发送信息
            sendMsg(msg);
            //收到bye时退出循环,结束该实例的线程
            if (msg.equals("bye")){
                break;
            }
        }
        //线程结束时关闭资源
        release();
        //从list中移除
        Server.list.remove(this);
        System.out.println("系统中还有"+ Server.list.size()+"个人在线");
        //Server.OnlineNum1--;
       // System.out.println("OnlineNum1"+Server.OnlineNum1);
        //发送系统提示信息
        sendSystemMsg(this.username + " 退出了聊天室");
    }

    
    private String receiveMsg() {
        String msg;
        try {
            msg = br.readLine();
            return msg;
        } catch (IOException e) {
            e.printStackTrace();
            //出现异常时返回空串
            return "";
        }
    }


    
    private void sendMsg(String msg) {
        //遍历list集合,向除本用户外的所有用户发送信息
        for (ServerThread st : Server.list) {

            if (!st.equals(this)) {
                st.pw.println(this.username + ":" + msg);

            }
        }
    }

    
    private void sendSystemMsg(String sysMsg) {
        //遍历list集合,向除本线程外的所有线程发送信息
        for (ServerThread st : Server.list) {
            if (!st.equals(this)) {

                st.pw.println(sysMsg);
            }
        }
    }

    
    private void release() {
        if (server != null) {
            try {
                server.close();
            } catch (IOException e) {

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

                        e.printStackTrace();
                    } finally {
                        if (pw != null) {
                            pw.close();
                        }
                    }
                }
            }
        }
    }
}

三、实验结果

客户端1

客户端二

服务端

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/694093.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号