Java和C++之间的socket通信 (springboot项目)

4 篇文章 0 订阅
1 篇文章 0 订阅

在翻阅了一万篇博客 浏览了n多个网站以后 终于被我整出来一个 还算稳定可靠的 tcp通信工具类了 各位觉得有帮助的可以点个收藏

2021年8月11日 16:37:56 记

本代码为个人总结 经过验证 可以实现 多个端口 多个地址的长连接通信 并做了比较多的代码冗余 加强代码的稳定性可以直接上手使用

注意:本文章只提供java客户端部分代码,c++部分为服务端代码 本人使用的为测试工具 并没有搭建相对应的服务器代码 如果有需要测试软件的

可以前往我的个人空间下载

下载地址:c++socket测试软件(客户端+服务器

话不多说 直接放代码

SocketClient 部分



/**
 * @author JingJian
 * @version 1.0
 * @date 2021/8/10 15:55
 */

import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.ClientAbortException;
import org.springframework.stereotype.Component;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

@Component
@Slf4j
public class SocketClient {

    private Socket client;

    //    socket连接列表 使用map保证唯一性
    private Map<String, Socket> clientList = new HashMap<>();

    AtomicInteger ai = new AtomicInteger(0);
    //    输出流
    private OutputStreamWriter writer;
    //    输入流
    private DataInputStream in;

    /*public SocketClient() {
        if (null == client) {
            synchronized (SocketClient.class) {
                if (null == client) {
                    try {
                        client = new Socket(host, port);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }*/

    /**
     * 创建新的连接
     *
     * @param host 请求地址
     * @param port 端口
     * @return
     */
    public Socket getClient(String host, Integer port) {
//        请求地址
        try {
            if (null == client) {
                synchronized (SocketClient.class) {
                    if (null == client) {
                        try {
                            client = new Socket(host, port);
//                            把socket的信息存到map里面
                            clientList.put((client.getInetAddress().toString().replaceAll("/", "") + client.getPort()), client);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
//                如果需要新增连接 则判断端口或者地址是否相等
            } else if (client.getPort() != port || !host.equals(client.getInetAddress().toString().replaceAll("/", ""))) {
//                遍历比较是否存在相对应的socket
                for (String key : clientList.keySet()) {
//                    存在相对应的socket
                    if (key.equals(host + port)) {
                        client = clientList.get(key);
                        return client;
                    }
                }
//                不存在相对应的socket
                try {
                    client = new Socket(host, port);
//                            把socket的信息存到map里面
                    clientList.put((client.getInetAddress().toString().replaceAll("/", "") + client.getPort()), client);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            log.error(e.toString());
        }
        return client;
    }

    /**
     * 发送消息
     *
     * @param msg 要发送的通知
     * @return
     */
    public String sendMsg(String host, Integer port, String msg) {

        getClient(host, port);
        //原子型锁,底层采用了锁机制
        try {
            in = new DataInputStream(client.getInputStream());
            writer = new OutputStreamWriter(client.getOutputStream(), "gbk");//将写入的字符编码成字节后写入一个字节流
            writer.write(msg);
            writer.flush();
//            new byte[5555] 5555 单次接收最长的字节数 目前没有找到更好的方法
            byte[] readResult = new byte[5555];
            in.read(readResult);
            String result = new String(readResult, "gbk");
//            判断是否socket服务强行中断 如果强行中断 则返回的为 指定长度的 '' char字符 如5555个null 此时取长度或者判空无效
            if (result.charAt(1) == '\0') {
                throw new NumberFormatException("服务异常中断");
            }
//            响应成功以后把错误次数计数清零
            ai.getAndSet(0);
            return result;
        } catch (Exception e) {
            log.error(e.toString());
            try {
//                在指定的异常里面重新创建连接
                if (e instanceof SocketTimeoutException || e instanceof NoRouteToHostException || e instanceof SocketException || e instanceof ConnectException || e instanceof NumberFormatException || e instanceof ClientAbortException) {
                    client = new Socket(host, port);
                }
            } catch (Exception ex) {
                log.error(e.toString());
            }
//            如果小于指定错误次数 则继续调用自身
            if (ai.get() < 10) {
//                原子自增
                ai.getAndIncrement();
              return this.sendMsg(host, port, msg);
            }
        }
        return "服务异常,请稍后重试!";
    }

    /**
     * 关闭连接
     */
    public void closeSocket() {
        try {
            client.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

调用部分

//注入
@Autowired
private SocketClient socketClient;

//具体使用方法
socketClient.sendMsg("127.0.0.1", 7777, "7777测试数据");

//具体使用方法 第二个
socketClient.sendMsg("127.0.0.1", 8891, "8891测试数据");

//手动关闭连接方法 一般web不需要关闭 服务停了就会自动关闭了 
socketClient.closeSocket();

测试结果:

 

 

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飓廴之莨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值