基于TCP协议的网络聊天室

创建服务端程序

public class Server {
    public static void main(String[] args) {
    
        new Thread(new ServerTask()).start(); //执行服务任务
        
    }
}

/**
*创建服务任务类
*/
class ServerTask implements Runnable {


    private ServerSocket serverSocket; //服务端口
    private List<Socket> clients; //客户端列表,用于保存所有客户端的socket

    public ServerTask() {
        try {
        
            serverSocket = new ServerSocket(6666); //初始化服务端口
            
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (serverSocket.isBound()) {
        
            System.out.println("服务器端口开启成功......");

        }

    }


    @Override
    public void run() {
    
        clients = new ArrayList<>(); //初始化客户端列表
        
        try {
        
            while (true) {//这里使用循环,一直处理用户请求
            
                Socket socket = serverSocket.accept(); //开始接收连接对象,没有用户请求挂起,阻塞。
                
                clients.add(socket); //有用户请求后,将该客户端的socket加入客户端列表
                
                new Thread(new HandlingClientCheat(socket)).start(); //开启线程处理聊天任务
            }

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

    }

    /**
     * 定义处理客户端信息的内部类
     */
    class HandlingClientCheat implements Runnable {
    
        private Socket socket; //该客户端的socket

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

        @Override
        public void run() {
            try {
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));   //获得网络输入流
                
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");     
                
                Date date = new Date();  //创建一个日期对象,可以显示信息时间
                
                String str;
                
                while ((str = reader.readLine()) != null) {

                        date.setTime(System.currentTimeMillis());//获取当前时间

                        str = simpleDateFormat.format(date) + "\n" + str;//格式化当前时间

                        System.out.println(str); //服务端输出聊天信息

						//给其他客户端转发此客户端的信息
                        for (Socket client : clients)
                            if (client != socket) {
                                PrintWriter writer = new PrintWriter(new OutputStreamWriter(client.getOutputStream()));
                                writer.println(str);
                                writer.flush();
                            }
                   

                }

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

        }
    }


}

创建客户端程序 | 搭建客户端界面

  • 客户端程序
public class Client {

   private ClientSendThread clientSendThread; //客户端发送信息线程
   private ClientFrame clientFrame; //所属的客户端界面
   private String username; //用户名

   public Client(ClientFrame clientFrame,String username){

       this.clientFrame = clientFrame;
       
       this.username = username;

       try {

           Socket socket = new Socket("localhost", 6666); //根据主机及端口号开启连接,并获得Socket对象
           if (socket.isConnected())
               clientFrame.showText.append("服务器连接成功.....\n\n");

           clientSendThread = new ClientSendThread(socket);

           clientSendTask.start();//创建并开启发送信息线程
           
           new ClientReceiveThread(socket).start();//创建并开启接收信息线程

       } catch (IOException e) {
           clientFrame.showText.append("服务器连接失败,请检查服务器是否开启.....");
           e.printStackTrace();
       }

   }

    public ClientSendThread getClientSendThread() {
        return clientSendTask;
    }

/**
*创建一个处理发送信息的内部类
*/
    class ClientSendThread extends Thread {

        private Socket socket; //此客户端的socket对象
        private String message; //此客户端发送的信息

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

        @Override
        public void run() {
            try {

                PrintWriter writer = new PrintWriter(socket.getOutputStream()); //获取网络输出流
                
                while (true) {
                
                    synchronized (this){
                        wait();  //这里先让此线程等待,知道客户端界面有内容输入就唤醒
                    }
                    
                    writer.println(username+":"+message);//将此用户发送的信息输出给服务端
                    
                    clientFrame.showText.append("\t\t\t\t\t\t\t\t\t我的:\n\t\t\t\t\t\t\t\t\t\t"+message+"\n\n");  //在对应的客户端界面显示信息
                    
                    message = null;  
                    
                    writer.flush(); //刷新输入流
                }

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

        public void setMessage(String message) {
            this.message = message;
        }
    }

/**
*创建客户端接收信息的内部类
*/
    class ClientReceiveThread extends  Thread {

        private Socket socket; //此客户端的socket对象

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

        @Override
        public void run() {
            try {
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); //获取网络输入流
                
                String str;
                
                while ((str = reader.readLine()) != null) {
                
                        clientFrame.showText.append(str+"\n\n"); //在客户端界面显示
                        clientFrame.showText.setCaretPosition(clientFrame.showText.getText().length());
                    
                }

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

    }

}
  • 搭建客户端界面

我这里搭建客户端界面使用的是JavaSwing

class ClientFrame extends JFrame {
    ClientFrame frame = this;
    JPanel inputBlock;
    JTextArea inputText;
    JTextArea showText;
    JScrollPane jScrollPane;
    JButton send;
    Client client;

    public static void main(String[] args) {
        new ClientFrame(); //开启客户端界面
    }

    public ClientFrame() {
        init();
        String username = JOptionPane.showInputDialog(this, "请输入一个用户名用于聊天", "提示", JOptionPane.INFORMATION_MESSAGE);
        setTitle("聊天室"+" 用户:"+username);
        client = new Client(this,username);  //创建客户端处理程序
    }

    void init() {
        //窗口设置
        setBounds(100, 100, 800, 600);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setDefaultLookAndFeelDecorated(true);
        setLayout(new GridLayout(2, 1));
        Container contentPane = getContentPane();


        //输入块
        inputBlock = new JPanel(null);


        //输入框
        inputText = new JTextArea(20, 20);
        inputText.setMargin(new Insets(10, 10, 10, 10));
        inputText.setFont(new Font("谐体", Font.BOLD, 16));
        inputText.setBounds(10, 10, 761, 230);

        //发送按钮
        send = new JButton("发送");
        send.setBounds(660, 243, 100, 30);


        inputBlock.add(inputText);
        inputBlock.add(send);


        //显示框
        jScrollPane = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        showText = new JTextArea("聊天记录\n\n");
        showText.setFont(new Font("宋体", Font.BOLD, 13));
        showText.setBackground(new Color(43, 43, 44));
        Border border = BorderFactory. createLineBorder(new Color(60, 63, 65));
        showText.setBorder(BorderFactory.createCompoundBorder(border, BorderFactory.createEmptyBorder(10, 10, 10, 10)));
        showText.setEnabled(false);

        jScrollPane.setViewportView(showText);

        //插入组件
        contentPane.add(jScrollPane);
        contentPane.add(inputBlock);

        setVisible(true);
        sendEvent();
    }

//组件的事件绑定
    public void sendEvent() {

//输入域的键盘事件
        inputText.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {

            }

            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyChar() == KeyEvent.VK_ENTER) {
                    sendMessage();
                }

            }

            @Override
            public void keyReleased(KeyEvent e) {

            }
        });
        
//发送按钮的点击事件
        send.addActionListener(l -> {
            sendMessage();
        });
    }

//发送信息的方法
    public void sendMessage() {
        String str = inputText.getText().trim();//获取到输入域的文本
        if (!str.equals("")) {
        
            client.getClientSendThread().setMessage(str);//设置客户端发送线程需要发送的信息。
            
            synchronized (client.getClientSendThread()) {
                client.getClientSendThread().notify(); //唤醒客户端发送线程
            }
            inputText.setText("");
            showText.setCaretPosition(showText.getText().length());
        }
    }

}

运行结果

用户张三

基于TCP协议的网络聊天室_第1张图片

用户李四

基于TCP协议的网络聊天室_第2张图片

用户王五:

基于TCP协议的网络聊天室_第3张图片

服务端

基于TCP协议的网络聊天室_第4张图片

总结:如此一个简单的基于TCP协议的网络聊天室就搭建好了。

你可能感兴趣的:(网络,tcp/ip,java)