网络聊天室1.0

一、聊天室的功能

服务器端

1.启动服务器,在服务器循环监听客户端

2.把循环接收的多个客户端Socket对象存储起来(Collection)

3.在服务器每个socket都要监听各自客户端发送的消息

4.在某个客户端发送了消息,服务器将此消息转发给其他客户端

客户端

1.用户登录(需要账号不为空即可),创建Socket----->未实现与数据库的连接(JDBC)

2.若Socket创建成功,打开聊天窗口

3.输入内容,点击发送按钮发送消息

4.客户端监听服务器端发送回来的消息并把消息显示出来

二、示例代码

创建一个新项目chatRoom:其中包含Client和Server两个Module

在这两个包中的src中分别创建新的包实现不同的功能:

Client

ChatFrame

package com.ffyc.chatroomclient;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ChatFrame extends JFrame {
    JTextArea chatArea;
    public ChatFrame(String account, Socket socket) throws IOException {
        //创建向客户端发送数据的数据输出流
        DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());

        // 创建主窗口
        JFrame frame = new JFrame("欢迎"+account+"加入聊天");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());

        // 创建公告面板
        JPanel announcementPanel = new JPanel();
        announcementPanel.setLayout(new BoxLayout(announcementPanel, BoxLayout.Y_AXIS));
        announcementPanel.setPreferredSize(new Dimension(300, 0)); // 设置公告面板的宽度
        announcementPanel.setBorder(BorderFactory.createTitledBorder("公告"));

        // 创建聊天窗口
        chatArea = new JTextArea();
        chatArea.setEditable(false);
        JScrollPane chatScrollPane = new JScrollPane(chatArea);
        chatScrollPane.setBorder(BorderFactory.createTitledBorder("聊天"));
        chatArea.setEditable(false);

        // 创建输入区域
        JPanel inputPanel = new JPanel();
        inputPanel.setLayout(new BorderLayout());
        JTextArea inputArea = new JTextArea(5, 20);


        inputArea.setLineWrap(true);
        JScrollPane jScrollPane = new JScrollPane(inputArea);
        JButton sendButton = new JButton("发送");

        inputPanel.add(jScrollPane, BorderLayout.CENTER);
        inputPanel.add(sendButton, BorderLayout.EAST);

        // 将组件添加到主窗口
        frame.add(announcementPanel, BorderLayout.WEST);
        frame.add(chatScrollPane, BorderLayout.CENTER);
        frame.add(inputPanel, BorderLayout.SOUTH);

        // 设置窗口大小并显示
        frame.setSize(800, 600);
        frame.setVisible(true);

        //来到聊天窗口后,可以开启一个线程监听服务器发送的消息
        new ClientThread(socket).start();

        //为发送按钮添加事件监听
        sendButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String message = inputArea.getText();
                if (message.length() == 0) {
                    JOptionPane.showMessageDialog(null, "输入内容不能为空!");
                    return;
                } //不为空,向服务器端发送消息
                String msg = account+" "+new SimpleDateFormat("HH:mm:ss").format(new Date())+"\n";
                        msg+=message;
                try {
                    dataOutputStream.writeUTF(msg);
                    inputArea.setText("");//清空发送内容
                } catch (IOException ex) {
                    ex.printStackTrace();
                    JOptionPane.showMessageDialog(null,"内容发送失败,请检查网络!");
                }
            }
        });
    }

    //线程监听服务器发送的消息
    class ClientThread extends Thread{
        boolean f = true;
        DataInputStream dataInputStream;
        public ClientThread(Socket socket) throws IOException {
            dataInputStream = new DataInputStream(socket.getInputStream());
        }

        @Override
        public void run() {
            while (f){
                try {
                    String msg = dataInputStream.readUTF();
                    chatArea.append(msg+"\n"); //显示聊天内容
                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println("服务器关闭");
                    f = false;
                }
            }
        }
    }
}

LoginFrame

package com.ffyc.chatroomclient;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.Socket;
import java.sql.Driver;
import java.sql.DriverManager;

public class LoginFrame extends JFrame {
    public LoginFrame() {
        this.setSize(350, 400);//设置窗口大小
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭窗口时退出程序
        this.setLocationRelativeTo(null);//设置窗口位置水平垂直居中
        this.setTitle("欢迎登陆");//设置窗口标题
        this.setResizable(true);//设置窗口为不可调整大小

        //创建登录面板
        JPanel allPanel = new JPanel(new GridLayout(4, 1, 5, 10));

        //欢迎面板
        JPanel welcomePanel = new JPanel();
        JLabel welcomeLabel = new JLabel("网络聊天室登录:");
        welcomePanel.add(welcomeLabel);

        //账户面板
        JPanel accountPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 40, 20));
        JLabel accountLabel = new JLabel("账户");
        JTextField accountTextField = new JTextField(15);
        accountPanel.add(accountLabel);
        accountPanel.add(accountTextField);

        //密码面板
        JPanel passwordPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 40, 20));
        JLabel passwordLabel = new JLabel("密码");
        JTextField passwordTextField = new JTextField(15);
        passwordPanel.add(passwordLabel);
        passwordPanel.add(passwordTextField);

        //注册面板
        JPanel registerPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 40, 20));
        JButton loginButton = new JButton("登录");
        JButton loginButton1 = new JButton("注册");
        registerPanel.add(loginButton);
        registerPanel.add(loginButton1);

        //把面板添加到总面板中
        allPanel.add(welcomePanel);
        allPanel.add(accountPanel);
        allPanel.add(passwordPanel);
        allPanel.add(registerPanel);

        //将面板添加到窗口中
        this.add(allPanel);
        this.setVisible(true);//设置窗口可视化,放在最后一行


        //为登录按钮添加事件监听
        loginButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //创建账号和密码
                String account = accountTextField.getText();
                if (account.length() == 0) {
                    JOptionPane.showMessageDialog(null, "账号不能为空!");
                    return;
                }
                String password = passwordTextField.getText();
                if (password.length() == 0) {
                    JOptionPane.showMessageDialog(null, "密码不能为空!");
                    return;
                }

                //后期预留与数据库交互

                //创建Socket
                try {
                    Socket socket = new Socket("127.0.0.1", 9999);
                    new ChatFrame(account,socket);//创建聊天窗口
                    dispose();//释放聊天窗口
                } catch (IOException ex) {
                    ex.printStackTrace();
                    JOptionPane.showMessageDialog(null, "服务器连接失败,请稍后再试");
                }


            }
        });
    }
}

Run

package com.ffyc.chatroomclient;

public class Run {
    public static void main(String[] args) {
        LoginFrame lf = new LoginFrame();
    }
}

Server

ServerDemo

package com.ffyc.chatroomserver;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class ServerDemo {


    //创建集合接收客户端口
    ArrayList<Socket> sockets = new ArrayList<>();

    public void startServer() {
        //创建服务器端
        try {
            ServerSocket serverSocket = new ServerSocket(9999);
            System.out.println("服务器启动成功");
            //监听客户端
            while (true) {
                Socket socket = serverSocket.accept();
                sockets.add(socket);
                System.out.println("有客户端连接,当前连接人数:" + sockets.size());

                //为每一个连接到服务器的客户端开启一个线程
                new SocketThread(socket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("服务器启动失败!");
        }
    }

    //创建一个内部类,继承Thread类,用于监听自己客户端有没有发送消息
  class SocketThread extends Thread {
        boolean f = true;
        Socket socket;
        DataInputStream dataInputStream;

        public SocketThread(Socket socket) throws IOException {
            this.socket = socket;
            dataInputStream = new DataInputStream(socket.getInputStream());
        }

        @Override
        public void run() {

            while (f) {//监听客户端发送的消息
                try {
                    String msg = dataInputStream.readUTF();
                    //向不同的客户端发送消息
                    for (Socket s:sockets){//遍历Socket集合
                        DataOutputStream dataOutputStream = new DataOutputStream(s.getOutputStream());
                        dataOutputStream.writeUTF(msg);
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println("客户端下线了");
                    sockets.remove(socket);
                    f = false;
                }
            }
        }
    }
}

ServerRun

package com.ffyc.chatroomserver;

public class ServerRun {
    public static void main(String[] args) {
        new ServerDemo().startServer();
    }
}

三、在做聊天室时遇到的问题

Client中的Run()不能同时多次运行

解决办法:找到idea2023中的Allow parallel run(允许同时运行)

1.点击Edit Configurations...

2.点击Modify options

3.勾选Allow mutiple instances

最后点击OK,问题就解决了

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值