用java实现一个简单的网络聊天室

这个小玩意儿很早之前就弄完了,计算机网络课设时候写的,最近才想起来还有个csdn账号,统一一下学习历程一并更新发了(这半年头发掉的太多了)。

那我们这个聊天室都由什么组成呢?

首先,基于B/S模型,你肯定得有一个server,然后至少两个client吧,我们先来看看server端怎么实现。ps:主要还是用socket通信那一套。

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class ChatServer {
    ArrayList clientOutPutStreams = new ArrayList();

    public static void main(String[] args) {
        new ChatServer().go();
    }

    public void go() {
        try {
            //server端创建出与client端通信的socket
            ServerSocket serverSocket = new ServerSocket(8888);
            System.out.println("服务器启动成功!");

            while (true) {
                //服务器创建出与客户端通信的socket
                Socket clientSocket = serverSocket.accept();
                String ip=clientSocket.getInetAddress().getHostAddress();
                System.out.println(ip+"加入了聊天室!");//控制台打印进入到聊天室的用户地址并提示

                //与客户端建立输出流,为以后给客户端写数据做准备
                PrintWriter printWriter = new PrintWriter(clientSocket.getOutputStream());
                clientOutPutStreams.add(printWriter);

                //开启一个线程用于与一个客户端进行通信
                Thread thread = new Thread(new clientHandler(clientSocket));

                //开启线程,使服务器一直处于接受消息并转发给所有人
                thread.start();

                System.out.println("有新连接加入");

            }

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

    public class clientHandler implements Runnable {
        BufferedReader reader;
        Socket socket;

        /**clientHandler的构造方法*/
        public clientHandler(Socket socket) {
            //与客户端建立通信并定义接受数据的输入流
            try {
                this.socket = socket;
                InputStreamReader inputStreamReader = new InputStreamReader(socket.getInputStream());
                reader = new BufferedReader(inputStreamReader);
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        /**开启线程之后要执行的run()方法*/
        @Override
        public void run() {
            //定义准备接受消息变量
            String message = null;

            try {
                //使线程不断从socket上读取数据的状态
                while ((message= reader.readLine())!=null){
                    System.out.println("MESSAGE_Receive: "+message);
                    //将数据发送给每一个客户端
                    sendEveryone(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

    /**给客户端发送消息的方法*/
    public void sendEveryone(String message){
        for (Object COPStreams: clientOutPutStreams) {
           try {
               PrintWriter writer = (PrintWriter) COPStreams;
               writer.println(message);
               writer.flush();
           }catch (Exception e){
               e.printStackTrace();
           }
        }
    }
}

 然后是客户端

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

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


public class ChatClient1 {
    JTextArea incoming;         //文本域,用来显示消息
    JTextField outgoing;        //输入框
    BufferedReader reader;      //缓冲字符输入流,用于读取服务器转发的消息
    PrintWriter writer;         //输出字符流,用于给服务器发消息
    Socket socket;              //创建准备与服务器连接的套接字


    public static void main(String[] args) {
        new ChatClient1().go();
    }

    public void go() {

        JFrame jFrame = new JFrame("聊天室客户端1");
        JPanel jPanel = new JPanel();

        //创建文本域
        incoming = new JTextArea(15, 22);
        incoming.setFont(new Font("微软雅黑",Font.BOLD,16));
        incoming.setLineWrap(true);        //设置在行过长时自动换行
        incoming.setWrapStyleWord(true);    //设置在单词过长时,将单词移到下一行
        incoming.setEditable(false);

        //创建滚动面板,并将文本域放入其中
        JScrollPane jScrollPane = new JScrollPane(incoming);
        jScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        jScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        //创建输入框
        outgoing = new JTextField(20);

        //创建发送按钮,并创建监听器
        JButton sendButton = new JButton("发送");
        sendButton.addActionListener(new sendButtonListener());

        //将上述定义组件放入JPanel容器中
        jPanel.add(jScrollPane);
        jPanel.add(outgoing);
        jPanel.add(sendButton);

        //将JPanel容器放入JFrame面板中
        jFrame.getContentPane().add(BorderLayout.CENTER, jPanel);
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jFrame.setSize(400,450);
        jFrame.setVisible(true);

        //与服务器建立连接
        setUpNetworking();

        //开启一个线程,并执行其中run()方法
        Thread thread = new Thread(new IncomingReader());
        thread.start();


    }


    /**
     * 与服务器建立socket连接,并在socket基础上建立输入流和输出流
     */
    private void setUpNetworking() {
        try {
            //与服务器socket建立连接
            socket = new Socket("127.0.0.1", 8888);

            //与socket建立字符缓冲输入流,用于接受发送框中的消息
            InputStreamReader inputStreamReader = new InputStreamReader(socket.getInputStream());
            reader = new BufferedReader(inputStreamReader);

            //与socket建立字符缓冲输出流,用于发送消息
            writer = new PrintWriter(this.socket.getOutputStream());
            incoming.append("客户端1成功连接到服务器......" + "\n");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 监听器与发送消息给服务器模块
     */
    class sendButtonListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            //当发送按钮点击,出发事件,将输入框中的文字获取,并发送给服务器
            writer.println("客户端1: " + outgoing.getText());
            writer.flush();

            //输入框文字清空
            outgoing.setText("");
            outgoing.requestFocus();
        }
    }

    /**
     * 该线程任务是不断读取服务器发送的信息,并将其加入到文本域中
     */
    class IncomingReader implements Runnable {
        public IncomingReader() {
        }

        @Override
        public void run() {
            String message;        //用于接受从服务器与客户端1建立的输入流中读出的信息
            try {
                while ((message = reader.readLine()) != null) {
                    System.out.println("接收到消息: " + message);
                    incoming.append(message + "\n");
                }

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

当然,再加一个客户端的话就是cv工作了,这里面可能有些对于多线程的把握还不是很好,后面可以再找时间优化优化。

你可能感兴趣的:(java,网络,开发语言,socket,多线程)