Java:打造简单实用的Socket工具类

在Java编程的世界中,网络通信是一个令人着迷的领域。无论是构建小型聊天应用还是实现复杂的分布式系统,掌握Socket编程都是至关重要的一步。然而,对于许多初学者来说,复杂的API和繁琐的实现细节往往让人望而却步。

下面是一个简单的使用Java实现Socket通信工具类的实现,希望对你有所帮助:

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class SocketUtil {
    private String host;
    private int port;

	/**
     * 构造函数
     * 
     * @param host 目标主机
     * @param port 目标端口
     */
    public SocketUtil(String host, int port) {
        this.host = host;
        this.port = port;
    }
    
    /**
     * 发送XML请求并接收响应
     * 
     * @param xmlRequest 要发送的XML报文
     * @return 包含RetCode和RetDes的响应对象
     * @throws Exception
     */
    public Response sendAndReceive(String xmlRequest) throws Exception {
        // 使用try-with-resources确保资源关闭
        try (Socket socket = new Socket(host, port)) {
            // 可以设置超时时间,例如10秒
            socket.setSoTimeout(10000);

            // 发送数据
            OutputStream output = socket.getOutputStream();
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8));

            String message = formatMessage(xmlRequest);
            writer.write(message);
            writer.flush();

            // 接收数据
            InputStream input = socket.getInputStream();
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();

            // 通常使用Socket最前面会有报文长度,这里假设前8位是报文长度,读取前8位报文长度
            byte[] lengthBytes = new byte[8];
            int totalRead = 0;
            while (totalRead < 8) {
                int read = input.read(lengthBytes, totalRead, 8 - totalRead);
                if (read == -1) {
                    throw new IOException("连接关闭,无法读取报文长度");
                }
                totalRead += read;
            }
            buffer.write(lengthBytes);
            
            // 读取报文内容长度
            String lengthStr = new String(lengthBytes, StandardCharsets.UTF_8);
            int length = Integer.parseInt(lengthStr.trim());

            // 读取报文内容
            byte[] bodyBytes = new byte[length];
            totalRead = 0;
            while (totalRead < length) {
                int read = input.read(bodyBytes, totalRead, length - totalRead);
                if (read == -1) {
                    throw new IOException("连接关闭,无法读取完整报文");
                }
                totalRead += read;
            }
            buffer.write(bodyBytes);

            // 输出缓存的所有内容
            byte[] allContent = buffer.toByteArray();
            System.out.println("接收到的全部内容:" + new String(allContent, StandardCharsets.UTF_8));

            // 分别处理各个部分
            String body = new String(bodyBytes, StandardCharsets.UTF_8);
            System.out.println("报文内容:" + body);

            // 解析XML
            return parseXml(body);
        }
    }

    // 示例方法,用于格式化消息
    private String formatMessage(String xmlRequest) {
        // 实现你的报文格式化逻辑,例如这里拼装发送报文的信息是8位报文长度+ 发送的xml格式报文
        int length = xml.getBytes("UTF-8").length;
        if (length > 99999999) {
            throw new IllegalArgumentException("XML报文长度超过最大限制(99999999字节)");
        }
        String lengthStr = String.format("%08d", length);
        return lengthStr + xml;
        return xmlRequest;
    }

    // 示例方法,用于解析XML
    private Response parseXml(String body) {
        // 实现你的XML解析逻辑
        // 这里示例获取xml格式报文的code,desc节点
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        // 解析XML内容
        Document doc = builder.parse(new ByteArrayInputStream(xml.getBytes("UTF-8")));

        // 获取code节点
        NodeList retCodeList = doc.getDocumentElement().getElementsByTagName("code");
        String retCode = (retCodeList.getLength() > 0) ? retCodeList.item(0).getTextContent() : null;

        // 获取code节点
        NodeList retDesList = doc.getDocumentElement().getElementsByTagName("desc");
        String retDes = (retDesList.getLength() > 0) ? retDesList.item(0).getTextContent() : null;
        return new Response(retCode, retDes); // 返回一个示例响应对象
    }

    // 示例响应类
    public static class Response {
        private String retCode;
        private String retDes;

        public Response(String retCode, String retDes) {
            this.retCode = retCode;
            this.retDes = retDes;
        }

        public String getRetCode() {
            return retCode;
        }

        public String getRetDes() {
            return retDes;
        }

        @Override
        public String toString() {
            return "Response [RetCode=" + retCode + ", RetDes=" + retDes + "]";
        }
    }

    public static void main(String[] args) {
        try {
            // 替换为实际的主机、端口和公司信息
            SocketUtil socketUtil = new SocketUtil("127.0.0.1", 8080);
            String xmlRequest = "<Request><Data>测试数据</Data></Request>";
            Response response = socketUtil.sendAndReceive(xmlRequest);
            System.out.println("响应结果: " + response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

注意

  1. 示例中使用byte类型接收返回的数据,也可以使用char类型,处理方式如下:
			// 接收数据
            InputStream input = socket.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));

            // 读取前8位报文长度
            char[] lengthChars = new char[8];
            int totalRead = 0;
            while (totalRead < 8) {
                int read = reader.read(lengthChars, totalRead, 8 - totalRead);
                if (read == -1) {
                    throw new IOException("连接关闭,无法读取报文长度");
                }
                totalRead += read;
            }
            String lengthStr = new String(lengthChars);
            int length = Integer.parseInt(lengthStr);

            // 读取报文内容
            char[] bodyChars = new char[length];
            totalRead = 0;
            while (totalRead < length) {
                int read = reader.read(bodyChars, totalRead, length - totalRead);
                if (read == -1) {
                    throw new IOException("连接关闭,无法读取完整报文");
                }
                totalRead += read;
            }
            String body = new String(bodyChars);

使用char类型接收时需注意长度,中英文长度不同,会导致按长度读取出错。需通信双方提前约定。

  1. 文章使用UTF-8编码格式,具体的编码格式,需双方约定。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值