All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.landuo.l4d2.utils.RconUtil Maven / Gradle / Ivy

package io.github.landuo.l4d2.utils;

import io.github.landuo.l4d2.entity.RconRequest;
import io.github.landuo.l4d2.enums.PacketTypeEnum;
import io.github.landuo.l4d2.exception.ServiceException;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * @author accidia
 * @see Source_RCON_Protocol
 */
public class RconUtil {

    /**
     * 发送指令到服务器上
     *
     * @param request 请求对象
     * @return 指令执行后的结果
     */
    public static String send(RconRequest request) {
        Socket socket = null;
        try {
            socket = new Socket();
            socket.connect(new InetSocketAddress(request.getIp(), request.getPort()), 2000);
        } catch (IOException e) {
            throw new ServiceException(e.getMessage(), e);
        }
        Random random = new Random();
        int id = random.nextInt();
        List array = new ArrayList<>();
        try {
            // 先进行认证
            write(socket.getOutputStream(), id, PacketTypeEnum.SERVERDATA_AUTH, request.getPasswd());
            read(id, socket.getInputStream());
            read(id, socket.getInputStream());
            id = random.nextInt();
            // 发送命令
            write(socket.getOutputStream(), id, PacketTypeEnum.SERVERDATA_EXECCOMMAND, request.getCmd());

            // 持续读数据
            socket.setSoTimeout(500);
            while (true) {
                array.add(read(id, socket.getInputStream()));
            }
        } catch (SocketTimeoutException socketTimeoutException) {
            try {
                socket.close();
            } catch (IOException e) {
                throw new ServiceException("Failed to close socket.");
            }
        } catch (IOException e) {
            throw new ServiceException(e.getMessage(), e);
        }
        StringBuilder builder = new StringBuilder();
        for (byte[] data : array) {
            builder.append(new String(data, StandardCharsets.UTF_8));
        }
        return builder.toString();

    }

    /**
     * 写命令到服务器上
     *
     * @param out            输出流
     * @param id             数据包的ID
     * @param packetTypeEnum 数据包的类型
     * @param body           数据包内容
     */
    private static void write(OutputStream out, Integer id, PacketTypeEnum packetTypeEnum, String body) {
        ByteBuffer bb = ByteBuffer.allocate(4 + 4 + 4 + body.getBytes().length + 2);
        bb.order(ByteOrder.LITTLE_ENDIAN);
        // 数据包大小
        bb.putInt(bb.limit() - 4);
        bb.putInt(id);
        bb.putInt(packetTypeEnum.getValue());
        bb.put(body.getBytes());
        //最后两位终止标志
        bb.put((byte) 0);
        bb.put((byte) 0);
        try {
            out.write(bb.array());
        } catch (IOException e) {
            throw new ServiceException("Failed to send cmd.");
        }
    }

    private static byte[] read(Integer id, InputStream in) throws IOException {
        byte[] header = new byte[4 * 3];
        in.read(header);
        ByteBuffer bb = ByteBuffer.wrap(header);
        bb.order(ByteOrder.LITTLE_ENDIAN);
        int packetSize = bb.getInt();
        int requestId = bb.getInt();
        if (requestId == -1) {
            throw new ServiceException(400, "Password error.");
        }
        if (requestId == id) {
            byte[] payload = new byte[packetSize - 4 - 4 - 2];
            DataInputStream dataInputStream = new DataInputStream(in);
            dataInputStream.readFully(payload);
            // 读取最后两个终止字符
            dataInputStream.read(new byte[2]);
            return payload;
        }
        return null;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy