通过Frame与Socket制作一个简易的聊天工具

实现思路:

1. 首先用frame设计一个窗口用于消息的发送与读取

2. socket发送消息一般有两部分,客户端与服务器,两个端可以UDP和TCP进行交互,这边我选用有连接的TCP协议

3. 只要多个客户端连接同一个服务器就可以进行一对一或一对多联通,所以设置了可配置动态的IP让使用者自行配置接入点,并且端口固定,只要是不同主机,端口相同并不会冲突

4. 将客户端与服务器绑在一起运行(可以适应张三想和李四聊,连接了李四的服务器。李四想跟王五聊,连接了王五的服务器)对方主动连接自己的服务器自己也可以收到推送,因为启动时可以先将自己的连接socket保存一份到服务器的List集合中,服务器通过List中存放的连接进行信息推送

效果如下

由于本人只有一台电脑,同时启动了两个所以地址是一样的。如果想要本地启动两个只需要将代码复制两份分开运行即可,但需要更改客户端的端口,因为会端口冲突。但是服务器不需要更改端口,冲突了会默认启动一台,要联通只需要一个服务端即可

代码实现如下,有注释可自行了解 

package com.example.mydemo;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 吴盈乐
 * @date 2022/6/13
 */
public class Demo37 {
    public static void main(String[] args) throws UnknownHostException {
        window client = new window("Client37");
    }

    private static String name;

    private static JTextField ipText;
    private static JTextField strText;
    private static JTextArea jTextArea;

    private static final List<Socket> sockets = new ArrayList<>();
    private static final Integer PORT = 6666;
    private static final Socket socket= new Socket();

    private static PrintWriter writer;
    private static BufferedReader reader;

    static class window extends Frame {

        //由于服务器需要优先启动所以设置在静态代码块中
        static {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    startServer();
                }
            }).start();
        }

        //设置聊天窗口0
        public window(String tilte) {
            super(tilte);
            name=tilte;
            setSize(350, 600);
            setBackground(Color.ORANGE);
            setLayout(new FlowLayout());

            //设置文本域
            jTextArea = new JTextArea(18, 28);
            jTextArea.setFont(new Font("monospaced", Font.PLAIN, 18));
            //只读
            jTextArea.setEditable(false);
            add(jTextArea);

            //设置滚动条
            JScrollPane textPanel = new JScrollPane(jTextArea);
            //textPanel.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
            //textPanel.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
            add(textPanel);

            //设置标签
            JLabel label = new JLabel("IP:");
            label.setPreferredSize(new Dimension(20, 50));
            add(label);

            //设置文本输入框
            ipText = new JTextField();
            ipText.setPreferredSize(new Dimension(160, 30));
            strText = new JTextField();
            strText.setPreferredSize(new Dimension(200, 30));
            add(ipText);
            add(strText);

            //设置点击按钮
            JButton button = new JButton();
            button.setText("发送");
            add(button);

            try {
                //设置启动端口与要连接的服务器地址、端口
                socket.bind(new InetSocketAddress(8081));
                socket.connect(new InetSocketAddress(ipText.getText(),6666));

                //创建打印流和字符缓冲输入流用于对信息的读取与写入
                writer = new PrintWriter(socket.getOutputStream());
                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                //创建线程来读取服务器推送的信息并添加到文本域,设置死循环让它一直更新信息
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            while (true){
                                jTextArea.append(reader.readLine()+ "\n");
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            } catch (IOException e) {
                e.printStackTrace();
            }

            setVisible(true);

            //设置监听事件,点击按钮时触发
            button.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (tilte.contains("Client")) {
                        client();
                    }
                    //清空输入框信息
                    ipText.setText("");
                    strText.setText("");
                }
            });

            //监听关闭聊天窗口
            addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    System.exit(0);
                }
            });
        }

        /**
         * 将从输入框获取到的信息发送到服务器
         */
        public static void client() {
            try {
                String mag = name+":"+strText.getText();
                while ("exit".equals(mag)){
                    writer.close();
                    reader.close();
                }
                writer.println(mag);
                writer.flush();

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

        /**
         * 用于启动服务器
         */
        public static void startServer() {
            try {
                ServerSocket serverSocket = new ServerSocket(PORT);
                //使其能够获取无限次的连接
                while (true) {
                    //用于阻塞直到有连接进入
                    Socket accept = serverSocket.accept();
                    //将socket连接存入集合中,用于后面的消息推送
                    sockets.add(accept);
                    //创建线程进行独立的消息分发给sockets中存放的各个客户端
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                boolean flag = true;
                                //通过转换流将字节进行字符转换,同时获取客户ip
                                BufferedReader reader = new BufferedReader(new InputStreamReader(accept.getInputStream()));
                                String ip = accept.getInetAddress().toString();
                                while (flag) {
                                    String s = reader.readLine();
                                    if ("exit".equals(s)) {
                                        flag = false;
                                        continue;
                                    }
                                    String msg = ip + ":" + s;
                                    send(msg);
                                }
                                sockets.remove(accept);
                                accept.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }

                        /**
                         * 消息分发
                         * @param msg 客户端IP+信息
                         * @throws IOException
                         */
                        private void send(String msg) throws IOException {
                            PrintWriter writer = null;
                            for (Socket socket : sockets) {
                                writer = new PrintWriter(socket.getOutputStream());
                                writer.println(msg);
                                writer.flush();
                            }
                        }
                    }).start();
                }

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

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值