Java实现Socket网络编程(四)

在看到本文之前,如果读者没看过笔者的前文Java实现Socket网络编程(三) ,请先翻阅。

下面,我们来实现服务器单体发送和广播发送:

我们为JList客户端列表设置监听,在每次点击触发时,先默认设置所有Socket未选中,避免错乱,然后获取全部已选中下标,并做好标记。笔者此处采用HashMap存储Socket,如Socket被选中,其对应Value为true,反之为false。

        // 添加监听
        clientList.addListSelectionListener(new ListSelectionListener() {

            @Override
            public void valueChanged(ListSelectionEvent e) {

                // 先默认把所有Socket未选中
                resetSocket(ListenThread.clientSockets);

                // 获取全部已选中下标
                int[] selecteds = clientList.getSelectedIndices();

                for (int i = 0; i < selecteds.length; i++) {
                    // 获取所选中项的HashMap
                    HashMap map = ListenThread.clientSockets
                            .get(selecteds[i]);
                    // 用迭代器获取HashMap的Key,即所选中的Socket
                    Iterator iter = map.entrySet().iterator();
                    Map.Entry entry = (Entry) iter
                            .next();
                    Socket key = (Socket) entry.getKey();
                    // 把所选中的Socket设置为true
                    map.replace(key, true);
                }
            }
        });

然后,在点击发送消息的按钮时,根据之前在JList中标记的Socket,向指定客户端发送消息。

        // 设置发送消息监听
        jbSendMessage.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {

                if (jtaSendMessage.getText().equals("")) {
                    JOptionPane.showMessageDialog(null, "发送内容不能为空!");
                    return;
                }

                if (jtaSendMessage.getText().length() > 5000) {
                    JOptionPane.showMessageDialog(null, "发送数据过大,最大不能超过5000字!");
                    return;
                }
                // 取得要发送的消息
                // 代表服务器正常连接
                String message = Common.OK;
                String t = "server " + Common.IP + ":" + Common.PORT + " "
                        + jtaSendMessage.getText();

                OutputStreamWriter outstream = null;
                // 将信息发送给每个选中的客户端
                for (int i = 0; i < ListenThread.clientSockets.size(); i++) {
                    try {
                        HashMap map = ListenThread.clientSockets
                                .get(i);
                        // 用迭代器获取HashMap的Key,即所选中的Socket
                        Iterator iter = map.entrySet().iterator();
                        Map.Entry entry = (Entry) iter
                                .next();

                        // 如果Socket已选中
                        if ((Boolean) entry.getValue()) {
                            Socket key = (Socket) entry.getKey();
                            outstream = new OutputStreamWriter(key
                                    .getOutputStream(), "GBK");
                            outstream.write(message);
                            outstream.flush();
                        }
                    } catch (IOException e1) {
                        if (outstream != null)
                            try {
                                outstream.close();
                            } catch (IOException e2) {
                                e2.printStackTrace();
                            }
                        e1.printStackTrace();
                    }
                }

                // 清空文本
                jtaSendMessage.setText(null);
            }
        });

为了实现客户端自动连接服务器,我们要为客户端实现一个子线程,用于轮询检测服务器是否已启动:

    public void run() {
        while (true) {

            // 窗口关闭则直接退出循环,避免在关闭过程中再次连接服务器
            if (ClientMain.isWindowClosing)
                break;

            try {
                if (ClientMain.mSocket == null || ClientMain.mSocket.isClosed()) {
                    ClientMain.isConnected = false;
                    ClientMain.jlConnect.setText("Out Of Connect.");
                }

                if (!ClientMain.isConnected) {
                    Socket socket = new Socket(Common.IP, Common.PORT);
                    ClientMain.mSocket = socket;
                    // 启动客户端连接子线程
                    new Thread(new ClientReceivedThread(socket)).start();
                    ClientMain.isConnected = true;
                    ClientMain.jlConnect.setText("Success Connect.");
                }
            } catch (Exception e) {
                // 无法连接服务器
                ClientMain.isConnected = false;
                ClientMain.jlConnect.setText("Out Of Connect.");
                e.printStackTrace();
            }
        }
    }

在这里,读者可能会遇到一个问题,客户端是如何检测到服务器断开,而服务器又如何检测到客户端断开呢?

笔者为读者提供两种方法:
1、检测读写错误,在BufferedReader的read()方法中,如果发生读写错误,便能捕获到。
2、发送心跳包检测

对于方法1,服务器和客户端实现的方法一样
对于方法2,服务器应发送心跳包0,客户端应发送心跳到0xFF

mSocket.sendUrgentData(0);//服务器检测客户端断开
mSocket.sendUrgentData(0xFF);//客户端检测服务器断开

当捕获到异常时,便能得知对方断开。

你可能感兴趣的:(Java实现Socket网络编程(四))