Java Socket Client

本文介绍了一种基于Socket的通信服务实现,包括初始化、发送和接收消息的完整流程。通过Spring框架和Lombok库简化了日志记录和组件注册。使用线程池管理消息队列,确保消息的可靠发送,并提供了错误处理机制。

import com.cmsen.common.socket.SocketThread;
import com.cmsen.common.util.ByteUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * @Author OWTS 
 * @Date 2020/8/25
 * @Description
 */
@Component
@Slf4j
public class SocketService {

    private static Socket socket = null;

    private static OutputStream dos = null;

    private static InputStream is = null;

    private boolean flag = false;

    private BlockingQueue<byte[]> queueMsg = new LinkedBlockingQueue<>();

    public SocketService() {
        SocketThread.create(this::initSocket).start();
    }

    private void initSocket() {
        try {
            log.warn("Socket Init:  " + "localhost : " + 2000);
            socket = new Socket("localhost", 2000);
            socket.setKeepAlive(true);
            dos = socket.getOutputStream();
            is = socket.getInputStream();
            if (socket.isConnected()) {
                log.warn("Socket Init Success:  " + "localhost : " + 2000);
            }
            SocketThread.create(this::message).start();
            SocketThread.create(this::reMessage).start();
        } catch (IOException e) {
            System.err.println(e.getMessage());
            log.warn("Socket Init Error:  " + "localhost : " + 2000);
            SocketThread.sleep(10000);
            initSocket();
        }
    }

    private void releaseSocket() {
        try {
            if (dos != null) {
                dos.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if (is != null) {
                is.close();

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if (socket != null) {
                socket.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        dos = null;
        is = null;
        socket = null;
    }

    public void sendMessage(int header, int type, int taskNo, int status, int tail) {
        byte[] message = ByteUtil.merger(
            ByteUtil.toBytes2(header),
            ByteUtil.toBytes2(type),
            ByteUtil.toBytes2(taskNo),
            ByteUtil.toBytes2(status),
            ByteUtil.toBytes2(tail)
        );
        queueMsg.offer(message);
    }

    public void message() {
        while (true) {
            if (!queueMsg.isEmpty()) {
                flag = false;
                int count = 0;
                byte[] bytes = queueMsg.poll();
                while (!flag && count < 5) {
                    log.warn("Send Message data: " + ByteUtil.toHex(bytes));
                    try {
                        dos.write(bytes);
                        dos.flush();
                        log.warn("Send Message success: " + ByteUtil.toHex(bytes));
                        count++;
                        Thread.sleep(3000);
                    } catch (Exception e) {
                        e.printStackTrace();
                        releaseSocket();
                        initSocket();
                    }
                }
                if (count > 4) {
                    System.out.println("System Error...");
                }
            }
        }
    }

    public void onMessage() {
        try {
            byte[] bytes = new byte[8];
            while ((is.read(bytes)) != -1) {
                String s = ByteUtil.toHex(bytes);
                flag = true;
                log.warn("Receiving Message >>>>" + ">>>>>>" + s);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void reMessage() {
        while (true) {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            onMessage();
        }
    }
}
<think>我们正在处理一个关于Java SocketClient忽略SSL证书验证的问题。根据用户提供的信息,他遇到了"unable to find valid certification path to requested target"错误,并且希望忽略SSL验证。需要注意的是,忽略SSL验证会带来安全风险,因此只建议在测试环境中使用。 在Java中,要忽略SSL证书验证,我们可以通过自定义SSLContext来实现,使用一个信任所有证书的TrustManager。这种方法适用于任何基于SSL/TLS的连接,包括WebSocket和普通的HTTPS连接。 以下是具体的步骤和代码示例: 1. 创建一个自定义的TrustManager,它不会对任何证书进行验证。 2. 初始化一个SSLContext,使用这个自定义的TrustManager。 3. 将SSLContext设置为默认的SSL上下文(可选,影响全局),或者只在你需要的连接中使用。 但是,请注意,用户提到的是使用SocketClient,这里我们假设用户使用的是基于Socket的SSL连接(如SSLSocket)。不过,在WebSocket的情况下,底层也是使用SSL/TLS,因此方法类似。 以下是一个完整的示例代码,展示如何忽略SSL证书验证: ```java import javax.net.ssl.*; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.cert.X509Certificate; public class SSLUtil { public static void disableCertificateValidation() { // 创建一个信任所有证书的TrustManager TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } public void checkClientTrusted(X509Certificate[] certs, String authType) { } public void checkServerTrusted(X509Certificate[] certs, String authType) { } } }; try { // 获取SSLContext实例,并使用自定义的TrustManager初始化 SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, trustAllCerts, new SecureRandom()); // 设置为默认的SSL上下文,这样所有的HttpsURLConnection都会使用 HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); // 设置默认的主机名验证器,忽略主机名验证 HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true); } catch (NoSuchAlgorithmException | KeyManagementException e) { e.printStackTrace(); } } } ``` 使用方式: 在建立连接之前调用`SSLUtil.disableCertificateValidation()`。这样,后续所有的HTTPS连接(包括WebSocket的wss连接)都会忽略SSL证书验证。 但是,请注意: - 这种方法会全局禁用SSL证书验证,包括主机名验证。因此,它会使你的应用程序容易受到中间人攻击。仅在测试环境中使用。 - 如果你只想针对特定的连接禁用验证,而不是全局,那么你需要为特定的连接设置SSLSocketFactory。例如,对于HttpsURLConnection,你可以这样: ```java URL url = new URL("https://example.com"); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); conn.setSSLSocketFactory(sslContext.getSocketFactory()); conn.setHostnameVerifier((hostname, session) -> true); ``` 对于WebSocket连接,如果你使用的是Java WebSocket API(如Tyrus),你可能需要设置一个自定义的SSLContext。具体方法取决于你使用的WebSocket客户端库。 另外,用户引用了[^1](http://stackoverflow.com/questions/2703161/how-to-ignore-ssl-certificate-errors-in-apache-httpclient-4-0),这个链接是关于Apache HttpClient 4.0忽略SSL证书错误的方法。但用户的问题是关于Java SocketClient的,所以我们没有采用HttpClient的方法。不过,如果用户使用的是HttpClient,那么方法会有所不同。 由于用户的问题是关于SocketClient的,我们提供了上述基于SSLContext的解决方案。 最后,再次强调:在生产环境中,请勿使用忽略证书验证的方法,而应该正确配置信任库,导入服务器证书或信任的CA证书。 相关问题: 1. 如何在Java中为特定的HTTPS连接忽略SSL证书验证? 2. 在Java中,如何将自签名证书导入信任库? 3. 使用Java WebSocket客户端时,如何忽略SSL证书验证?</think>### Java SocketClient 忽略 SSL 证书验证解决方案 当需要在 Java `SocketClient` 中忽略 SSL 证书验证时(**仅限测试环境使用**),可通过自定义 `TrustManager` 实现。以下是完整实现方案: #### 核心代码实现 ```java import javax.net.ssl.*; import java.security.SecureRandom; import java.security.cert.X509Certificate; public class SSLIgnoreUtil { // 创建信任所有证书的 TrustManager private static final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } public void checkClientTrusted(X509Certificate[] certs, String authType) { // 空实现 - 信任所有客户端证书 } public void checkServerTrusted(X509Certificate[] certs, String authType) { // 空实现 - 信任所有服务器证书 } } }; // 创建忽略主机名验证的 HostnameVerifier private static final HostnameVerifier trustAllHostnames = (hostname, session) -> true; // 始终返回 true // 获取忽略验证的 SSLContext public static SSLContext createIgnoreSSLContext() throws Exception { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustAllCerts, new SecureRandom()); return sslContext; } // 应用全局忽略设置 (慎用!) public static void disableGlobalSSLVerification() throws Exception { SSLContext.setDefault(createIgnoreSSLContext()); HttpsURLConnection.setDefaultHostnameVerifier(trustAllHostnames); } } ``` #### 使用方式 1. **方法一:针对单个连接** ```java // 创建自定义 SSLContext SSLContext sslContext = SSLIgnoreUtil.createIgnoreSSLContext(); // 创建 SSLSocketFactory SSLSocketFactory factory = sslContext.getSocketFactory(); // 建立 SSL 连接 Socket socket = factory.createSocket("example.com", 443); ``` 2. **方法二:全局设置(影响所有连接)** ```java // 应用全局设置(启动时调用一次) SSLIgnoreUtil.disableGlobalSSLVerification(); // 后续所有连接自动忽略验证 Socket socket = SSLSocketFactory.getDefault().createSocket("example.com", 443); ``` #### 注意事项 1. **安全警告** ⚠️ 此方案会**完全禁用 SSL/TLS 证书验证**,使连接暴露于中间人攻击风险中[^1]。仅限以下场景使用: - 测试环境 - 访问受控内网服务 - 临时调试 - **禁止在生产环境使用** 2. 兼容性说明 ```mermaid graph LR A[Java 版本] --> B[Java 6+] A --> C[Java 7+ 推荐] D[协议支持] --> E[TLSv1.2] D --> F[TLSv1.3] ``` 3. 最佳实践 - 优先使用证书导入方案(参考之前回答的 `keytool` 方法) - 为不同服务创建独立 `SSLContext` 实例 - 使用后立即重置默认设置: ```java // 恢复默认验证 SSLContext.setDefault(null); HttpsURLConnection.setDefaultHostnameVerifier(null); ``` #### 替代方案:仅忽略过期证书 ```java // 在 SSLIgnoreUtil 中添加此方法 public static SSLContext createIgnoreExpiredSSLContext() throws Exception { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[] { new X509ExtendedTrustManager() { public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) { // 仅检查证书是否过期 for (X509Certificate cert : chain) { cert.checkValidity(); } } // 其他必要方法实现... } }, new SecureRandom()); return sslContext; } ``` > **关键提示**:即使忽略证书验证,仍建议检查证书有效期以防止过期证书导致的意外中断[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值