用java编写一个网络聊天室

网络聊天室

服务器:

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

try {
            ServerSocket serverSocket=new ServerSocket(6622);
            System.out.println("服务器已启动");
            while(true){//把客户端实例添加到sockets里
                Socket socket=serverSocket.accept();
                sockets.add(socket);
                System.out.println("当前连接到客户端数量:"+sockets.size());

                //为每一个链接过来的客户端开一个线程
                new SocketThread(socket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("服务器创建失败");
        }

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

ArrayList<Socket> sockets=new ArrayList<>();

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

while(true){
                try {
                    String msg=dataInputStream.readUTF();
                    jTextAreamsg.append(msg+"\n");//在服务器端显示msg
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println("客户端下线了");
                }
            }

4.一旦某个客户端发送了消息,那么在服务器端,就将此消息转发给其他的客户

//向不同客户端转发消息
                    //遍历sockets
                    for (Socket socket:sockets){//客户端1 客户端2 客户端3
                        DataOutputStream dataOutputStream=new DataOutputStream(socket.getOutputStream());
                        dataOutputStream.writeUTF(msg);
                    }
客户端:

1.用户登录,创建Socket

 Socket socket = new Socket("xxxxxxxxx", 6622);

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

new ChatWindow(jTextaccount.getText(), socket);//打开聊天窗口

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

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

class ClientThread extends Thread{
        DataInputStream dataInputStream;
        public ClientThread(Socket socket) throws IOException {
            dataInputStream=new DataInputStream(socket.getInputStream());
        }

        @Override
        public void run() {
            while(true){
                try {
                    String msg=dataInputStream.readUTF();
                    jTextArea.append(msg+"\n");//可以显示聊天内容并且保持原先内容
                } catch (IOException e) {
                    e.printStackTrace();
                    break;
                }
            }
        }
    }

完整代码:

ChatWindow:

public class ChatWindow extends JFrame {
    JTextArea jTextArea;
    public ChatWindow(String name, Socket socket) throws IOException {
        DataOutputStream dos=new DataOutputStream(socket.getOutputStream());
        this.setTitle("欢迎"+name+"登录");
        this.setSize(500,500);
        this.setLocationRelativeTo(null);//居中
        this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);//关闭窗口时退出程序
        this.setResizable(false);//禁止窗口拖拽

        //创建面板
        JPanel jPanel=new JPanel();
        jTextArea=new JTextArea(22,43);//显示文本域
        jTextArea.setEditable(false);//不可修改的
        JTextArea jTextArea2=new JTextArea(5,33);//发送文本域
        jTextArea2.setLineWrap(true);//强制换行
        JScrollPane j=new JScrollPane(jTextArea2);//滚动条
        JButton jButtonsend=new JButton("发送");

        jPanel.add(jTextArea);
        jPanel.add(j);
        jPanel.add(jButtonsend);


        this.add(jPanel);

        this.setVisible(true);

        //来到聊天窗口

        jButtonsend.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String message=jTextArea2.getText();
                if(message.length()==0){//输入为空
                    JOptionPane.showMessageDialog(null,"发送内容不能为空");
                    return;
                }
                else{
                    //不为空,向服务器发送消息
                    String msg=name+"  "+new SimpleDateFormat("HH:mm:ss").format(new Date());
                    msg=msg+"\n"+message;
                    try {
                        dos.writeUTF(msg);
                        //发送成功清空发送内容
                        jTextArea2.setText("");
                    } catch (IOException ioException) {
                        ioException.printStackTrace();
                        JOptionPane.showMessageDialog(null,"内容发送失败,请检查网络连接");
                    }
                }
            }
        });
        new ClientThread(socket).start();
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                int res=JOptionPane.showConfirmDialog(null,"你确定要退出聊天吗?","警告",JOptionPane.OK_CANCEL_OPTION);
                if(res==0){
                    //点击确定
                    new LoginWindow();
                    dispose();
                }
            }
        });
    }

    //监听服务器发的消息(即客户端123的消息)
    class ClientThread extends Thread{
        DataInputStream dataInputStream;
        public ClientThread(Socket socket) throws IOException {
            dataInputStream=new DataInputStream(socket.getInputStream());
        }

        @Override
        public void run() {
            while(true){
                try {
                    String msg=dataInputStream.readUTF();
                    jTextArea.append(msg+"\n");//可以显示聊天内容并且保持原先内容
                } catch (IOException e) {
                    e.printStackTrace();
                    break;
                }
            }
        }
    }

}

LoginWindow:

public class LoginWindow extends JFrame {
    public LoginWindow(){
        this.setTitle("欢迎登录");
        this.setSize(500,350);
        this.setLocationRelativeTo(null);//居中
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭窗口时退出程序
        this.setResizable(false);//禁止窗口拖拽

        JPanel jPanel=new JPanel();
        JLabel jLabel=new JLabel("欢迎登录");
        jLabel.setFont(new Font("横体", Font.BOLD,30));
        jPanel.add(jLabel);//欢迎登录

        //中间第一个空标签
        JLabel jLabel1=new JLabel();//欢迎登录下面空白部分
        jLabel1.setPreferredSize(new Dimension(500,50));

        //账号
        JLabel jLabelAccount=new JLabel("账号");//账号标签
        jLabelAccount.setPreferredSize(new Dimension(30,30));
        JTextField jTextaccount=new JTextField(15);//账号文本域


        //中间第二个空标签
        JLabel jLabel2=new JLabel();//欢迎登录下面空白部分
        jLabel2.setPreferredSize(new Dimension(500,20));

        //密码
        JLabel jLabelPassword=new JLabel("密码 ");//账号标签
        jLabelPassword.setPreferredSize(new Dimension(30,30));
        JPasswordField jPasswordField=new JPasswordField(15);

        //中间第二个空标签
        JLabel jLabel3=new JLabel();//欢迎登录下面空白部分
        jLabel3.setPreferredSize(new Dimension(500,20));

        //按钮
        JButton ButtonLogin=new JButton("登录");
        JButton ButtonSign=new JButton("注册");

        jPanel.add(jLabel1);
        jPanel.add(jLabelAccount);
        jPanel.add(jTextaccount);
        jPanel.add(jLabel2);
        jPanel.add(jLabelPassword);
        jPanel.add(jPasswordField);
        jPanel.add(jLabel3);
        jPanel.add(ButtonLogin);
        jPanel.add(ButtonSign);
        this.add(jPanel);
        this.setVisible(true);

        //按钮事件
        ButtonLogin.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if(jTextaccount.getText().equals("")||jPasswordField.getText().equals("")){//当账号或密码为空时,弹出警告
                    JOptionPane.showMessageDialog(null,"账号和密码不能为空","警告",JOptionPane.ERROR_MESSAGE);
                    return;
                }
                else if(!((jTextaccount.getText().matches("\\w{1,100}"))&&(jPasswordField.getText().matches("\\w{1,100}")))){//当1-100范围内不是字母和数字时弹出警告
                    JOptionPane.showMessageDialog(null,"账号密码只能由数字,字母组成","警告",JOptionPane.ERROR_MESSAGE);
                    return;
                }
                //创建Socket
                else {
                    try {
                        Socket socket = new Socket("10.13.0.67", 6622);
                        new ChatWindow(jTextaccount.getText(), socket);//打开聊天窗口
                        dispose();//释放窗口
                    } catch (IOException ioException) {
                        ioException.printStackTrace();
                        JOptionPane.showMessageDialog(null, "服务器连接失败,请稍后再试");
                    }
                }
            }

        });
    }
}

Run:

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

Server:

public class Server extends JFrame {

    JTextArea jTextAreamsg;//放到成员变量便于在内部类中也可以使用
    //客户端连接的数量
    ArrayList<Socket> sockets=new ArrayList<>();

    public void ServerStart(){
        this.setTitle("我是服务器");
        this.setSize(500,500);
        this.setLocationRelativeTo(null);//居中
        this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);//关闭窗口时退出程序
        this.setResizable(false);//禁止窗口拖拽

        JPanel jPanel=new JPanel();
        jTextAreamsg=new JTextArea(28,43);
        jTextAreamsg.setLineWrap(true);//强制换行
        JScrollPane jScrollPane=new JScrollPane();
        jTextAreamsg.setEditable(false);//不可修改的

        jPanel.add(jTextAreamsg);
        jPanel.add(jScrollPane);

        this.add(jPanel);
        this.setVisible(true);

        //关闭窗口
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                int res=JOptionPane.showConfirmDialog(null,"你确定要关闭服务器吗?","警告",JOptionPane.OK_CANCEL_OPTION);
                if(res==0){//点击确定
                    dispose();
                }
            }
        });

        try {
            ServerSocket serverSocket=new ServerSocket(6622);
            System.out.println("服务器已启动");
            while(true){//把客户端实例添加到sockets里
                Socket socket=serverSocket.accept();
                sockets.add(socket);
                System.out.println("当前连接到客户端数量:"+sockets.size());

                //为每一个链接过来的客户端开一个线程
                new SocketThread(socket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("服务器创建失败");
        }
    }




    //内部类,用来监听自己客户端有没有发消息
    class SocketThread extends Thread{
        Socket socket;//用来引入到run方法
        DataInputStream dataInputStream;
        public SocketThread(Socket socket) throws IOException {
            this.socket=socket;//把成员变量socket赋值为传入的socket参数,以便于客户端下线后可以从sockets里移除客户端
            dataInputStream=new DataInputStream(socket.getInputStream());
        }

        @Override
        public void run() {
            //循环监听客户端自己发送消息
            while(true){
                try {
                    String msg=dataInputStream.readUTF();
                    jTextAreamsg.append(msg+"\n");//在服务器端显示msg
                    //向不同客户端转发消息
                    //遍历sockets
                    for (Socket socket:sockets){//客户端1 客户端2 客户端3
                        DataOutputStream dataOutputStream=new DataOutputStream(socket.getOutputStream());
                        dataOutputStream.writeUTF(msg);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println("客户端下线了");
                    sockets.remove(socket);
                    break;
                }
            }
        }
    }
}

ServerRun:

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

在这个过程中监听服务器消息和监听客户端消息都用到了内部类,这样的好处是可以之间在内部类中使用大类里面的jTextArea和sockets

你可能感兴趣的:(java,网络,python)