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<Socket, Boolean> map = ListenThread.clientSockets
                            .get(selecteds[i]);
                    // 用迭代器获取HashMap的Key,即所选中的Socket
                    Iterator iter = map.entrySet().iterator();
                    Map.Entry<Socket, Boolean> entry = (Entry<Socket, Boolean>) 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<Socket, Boolean> map = ListenThread.clientSockets
                                .get(i);
                        // 用迭代器获取HashMap的Key,即所选中的Socket
                        Iterator iter = map.entrySet().iterator();
                        Map.Entry<Socket, Boolean> entry = (Entry<Socket, Boolean>) 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);//客户端检测服务器断开

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,099评论 19 139
  • 7.2 面向套接字编程我们已经通过了解Socket的接口,知其所以然,下面我们就将通过具体的案例,来熟悉Socke...
    lucas777阅读 1,208评论 0 2
  • 目录一、socket是什么,socket和HTTP的区别二、如何建立一个socket连接三、使用CocoaAsyn...
    意一ineyee阅读 1,668评论 0 13
  • 灰姑娘的故事原在欧洲民间广为流传,在欧洲,《灰姑娘》的最早版本名为《La Gatta Cenerentola》,也...
    肆點柒阅读 5,047评论 21 30