Java BIO tcp服务端向客户端消息群发代码教程实战

简介: java BIO tcp服务端向客户端消息群发代码教程实战

前言

  项目需要和第三方厂商的服务需要用TCP协议通讯,考虑到彼此双方可能都会有断网重连、宕机重启的情况,需要保证 发生上述情况后,服务之间能够自动实现重新通信。研究测试之后整理如下代码实现。因为发现客户端重启后,对于服务端来说原来的客户端和服务端进程进程已经关闭,启动又和服务端新开了一个进程。所以实现原理就可以通过服务端向客户端群发实现,断开重新连接通讯。

代码

tcp服务端代码

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class HttpSocketServer {
    public static void main(String[] args) {
        try {
            ServerSocket server=new ServerSocket(9020);
            while (true){
                Socket client=server.accept();
                client.setKeepAlive(true);
                client.setOOBInline(true);
                System.out.println("进入了1个客户机连接:"+client.getRemoteSocketAddress().toString());
                ServerThread st = new ServerThread(client);
                st.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

image.gif

ServerThread 线程类

import java.io.*;
import java.net.Socket;
/**
 * 客户机   线程 ——自动执行run
 * @author Lenovo
 */
public class ServerThread extends Thread{
    private Socket client;
    /**
     * 方法描述: 用有参构造  接收主函数那边传来的 客户机
     */
    public ServerThread(Socket client) {
        this.client=client;
    }
    @Override
    public void run() {
        try {
            processSocket();//调用你想执行的 使线程启动时在run方法开始执行
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 调用以上方法
     */
    public void processSocket() throws IOException {
        //加入集合 便于服务器群发
        TcpTool.addSocket(client);
    }

image.gif

TcpTool 消息群发工具类

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
/**
 * 聊天工具类
 * @author tarzan
 */
public class TcpTool {
    private static List<Socket> clientList=new ArrayList<Socket>();
    /**
     * 便于 验证成功后  加入客户机
     * @param socket
     */
    public static void addSocket(Socket socket) {
        clientList.add(socket);
    }
    /**
     * 群发=遍历list中的all元素, 对每个元素 写出
     * @param msg
     * @throws IOException
     */
    public static void sendAll(String msg){
        for (int i = 0; i <clientList.size(); i++) {
            Socket client = clientList.get(i);
            if(clientIsClose(client)){
                delSocket(client);
                i--;
                continue;
            }
            try {
                OutputStream ops =  client.getOutputStream();
                ops.write((msg+"\r\n").getBytes());
                ops.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 判断是否断开连接,断开返回true,没有返回false
     * @param socket
     * @return
     */
    public static Boolean clientIsClose(Socket socket){
        try{
            //发送1个字节的紧急数据,默认情况下,服务器端没有开启紧急数据处理,不影响正常通信
            socket.sendUrgentData(0xFF);
            // 发送一个数据包, 如果通信正常就不会报错.  没有报错说明没有关闭., 返回false
            return false;
        }catch(Exception se){
            return true;
        }
    }
    /**
     * 下线时删除
     * @param socket
     */
    public static void delSocket(Socket socket){
        clientList.remove(socket);
    }
}

image.gif

Tcp客户端代码

import org.springblade.core.tool.utils.StringUtil;
import java.io.*;
import java.net.Socket;
/**
 * @author tarzan
 */
public class HttpSocketClient {
    public static void main(String[] args) throws IOException {
        Socket client=new Socket("127.0.0.1",9020);
        client.setKeepAlive(true);
        client.setOOBInline(true);
        while (true) {
            try {
                if (!clientIsClose(client)) {
                    InputStream is=client.getInputStream();
                    BufferedReader reader=new BufferedReader(new InputStreamReader(is));
                    String text=reader.readLine();
                    if(StringUtil.isNotBlank(text)){
                        System.out.println("来自服务端的消息:"+text);
                    }
                }else{
                    try {
                        //断开5秒后重新连接
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    client=new Socket("127.0.0.1",9020);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public static Boolean clientIsClose(Socket socket){
        try{
            //发送1个字节的紧急数据,默认情况下,服务器端没有开启紧急数据处理,不影响正常通信
            socket.sendUrgentData(0xFF);
            // 发送一个数据包, 如果通信正常就不会报错.  没有报错说明没有关闭., 返回false
            return false;
        }catch(Exception se){
            return true;
        }
    }

image.gif

运行一个服务端,启动多个客户端进行测试。

控制台输出

image.gif编辑

以上只是实现的最简单的demo,服务端,因为服务端和客户端都需要不断监听彼此通信,发送消息时候,需要另起一个线程,调用TcpTool工具类想客户端群发消息。

相关文章
|
3天前
|
自然语言处理 Java API
Java 8的Stream API和Optional类:概念与实战应用
【5月更文挑战第17天】Java 8引入了许多重要的新特性,其中Stream API和Optional类是最引人注目的两个。这些特性不仅简化了集合操作,还提供了更好的方式来处理可能为空的情况,从而提高了代码的健壮性和可读性。
26 7
|
5天前
|
Web App开发 JavaScript 前端开发
《手把手教你》系列技巧篇(三十九)-java+ selenium自动化测试-JavaScript的调用执行-上篇(详解教程)
【5月更文挑战第3天】本文介绍了如何在Web自动化测试中使用JavaScript执行器(JavascriptExecutor)来完成Selenium API无法处理的任务。首先,需要将WebDriver转换为JavascriptExecutor对象,然后通过executeScript方法执行JavaScript代码。示例用法包括设置JS代码字符串并调用executeScript。文章提供了两个实战场景:一是当时间插件限制输入时,用JS去除元素的readonly属性;二是处理需滚动才能显示的元素,利用JS滚动页面。还给出了一个滚动到底部的代码示例,并提供了详细步骤和解释。
32 10
|
1天前
|
JavaScript 前端开发 Java
《手把手教你》系列技巧篇(四十九)-java+ selenium自动化测试-隐藏元素定位与操作(详解教程)
【5月更文挑战第13天】本文主要讨论了在Selenium自动化测试中如何处理前端隐藏元素的问题。隐藏元素通常是通过`type="hidden"`或`style="display: none;"`属性实现的,它们在页面上不可见,但仍然存在于HTML代码中。Selenium可以定位到这些隐藏元素,但无法直接进行点击、输入等操作,会报错“ElementNotInteractableException”。
18 3
|
2天前
|
JavaScript 前端开发 测试技术
《手把手教你》系列技巧篇(四十八)-java+ selenium自动化测试-判断元素是否可操作(详解教程)
【5月更文挑战第12天】本文介绍了WebDriver中用于判断元素状态的三个方法:`isEnabled()`、`isSelected()`和`isDisplayed()`。`isSelected()`检查元素是否被选中,通常用于勾选框。`isDisplayed()`则用来判断元素是否在页面上可见。`isEnabled()`方法确定元素是否可操作,例如是否能点击或输入内容。
11 1
|
3天前
|
存储 JavaScript Java
《手把手教你》系列技巧篇(四十七)-java+ selenium自动化测试-判断元素是否显示(详解教程)
【5月更文挑战第11天】WebDriver 的 `isDisplayed()` 方法用于检查页面元素是否可见,如果元素存在于DOM中且可视,返回`true`,否则返回`false`。在自动化测试中,这个方法常用于验证元素是否真正显示在页面上。示例代码展示了如何使用 `isDisplayed()` 判断百度登录页面的特定错误提示文字是否出现。
14 1
|
4天前
|
JavaScript Java 测试技术
《手把手教你》系列技巧篇(四十六)-java+ selenium自动化测试-web页面定位toast-下篇(详解教程)
【5月更文挑战第10天】本文介绍了使用Java和Selenium进行Web自动化测试的实践,以安居客网站为例。最后,提到了在浏览器开发者工具中调试和观察页面元素的方法。
14 2
|
4天前
|
算法 Java Python
保姆级Java入门练习教程,附代码讲解,小白零基础入门必备
保姆级Java入门练习教程,附代码讲解,小白零基础入门必备
|
4天前
|
Web App开发 JavaScript 测试技术
《手把手教你》系列技巧篇(四十五)-java+ selenium自动化测试-web页面定位toast-上篇(详解教程)
【5月更文挑战第9天】本文介绍了在Appium中处理App自动化测试中遇到的Toast元素定位的方法。Toast在Web UI测试中也常见,通常作为轻量级反馈短暂显示。文章提供了两种定位Toast元素的技巧.
11 0
|
5天前
|
Web App开发 缓存 前端开发
《手把手教你》系列技巧篇(四十四)-java+ selenium自动化测试-处理https 安全问题或者非信任站点-下篇(详解教程)
【5月更文挑战第8天】这篇文档介绍了如何在IE、Chrome和Firefox浏览器中处理不信任证书的问题。作者北京-宏哥分享了如何通过编程方式跳过浏览器的证书警告,直接访问不受信任的HTTPS网站。文章分为几个部分,首先简要介绍了问题背景,然后详细讲解了在Chrome浏览器中的两种方法,包括代码设计和运行效果,并给出了其他浏览器的相关信息和参考资料。最后,作者总结了处理此类问题的一些通用技巧。
16 2
|
5天前
|
Java Android开发
【Java开发指南 | 第十八篇】Eclipse安装教程
【Java开发指南 | 第十八篇】Eclipse安装教程
14 2