Skip to main content

sponge通过socket与QQ群进行消息互通

写在前面

minecraft服务器的聊天消息和qq机器人互通这件事,之前也做过:基于socket的酷Q机器人与Minecraft消息同步功能的实现

但是啊,这个插件当时长时间使用之后,发现会卡服。。。。由此可见当时写的代码有多么垃圾。

另外一个原因就是现在更新到了sponge服务器,不是之前的bukkit/spigot服务端了,插件并不会兼容。所以我根据官网教程又重写简单地写了一下。

说实话,我并不会java,是完全不会的那种不会

实现了什么

sponge端,使用java编写了一个socket客户端,并在掉线时自动重连

c#端,直接用现成的库做了个soket服物端,启动插件后自动开启,并将相应传递给lua文件,给lua提供发送接口

java代码

这部分实现就基本按照官方文档+网上找的代码拼凑起来了。就像上面说的:我并不会java。我做的事情就是找几个需要的部分,能跑起来,最后拼到一起

socket客户端

客户端直接用了现成的代码,网上找的,稍微自己改了改把心跳那个判断去掉了:

class Client {
    public Socket socket = null;
    public OutputStream os = null;
    public InputStream is = null;

    /**
     * 发送心跳包
     */
    public void sendHeartbeat() {
        try {
            String heartbeat = "h";
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        try {
                            Thread.sleep(120 * 1000);// 120s发送一次心跳
                            os.write(heartbeat.getBytes());
                            os.flush();
                        } catch (Exception e) {
                            //e.printStackTrace();
                            System.out.println("heartbeat send error");
                            try {
                                socket.close();
                                is.close();
                                os.close();
                            } catch (IOException e1) {
                                e1.printStackTrace();
                            }
                        }
                    }
                }
            }).start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public class SocketThread extends Thread {
        @Override
        public void run() {
            sendHeartbeat();
            while (true) {
                try {
                    if (socket == null || socket.isClosed()) {
                        socket = new Socket("localhost", 23333); // 连接socket
                        os = socket.getOutputStream();
                        System.out.println("socket connected");
                    }
                    Thread.sleep(100);
                    is = socket.getInputStream();
                    int size = is.available();
                    if(size <= 0)
                        continue;
                    byte[] resp = new byte[size];
                    is.read(resp);
                    String response = new String(resp,"utf8");
                    try{
                        MessageChannel.TO_ALL.send(Text.of(response));
                    }
                    catch (Exception e){

                    }
                    //Logger.info("receive data:" + response);
                } catch (Exception e) {
                    //e.printStackTrace();
                    System.out.println("socket error");
                    try {
                        socket.close();
                        is.close();
                        os.close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        }
    }
}

然后写一下开启服务器使用的函数,在插件的主类里写:

private Client tcpClient = null;
public void StartServer()
{
    logger.info("starting tcp client");
    tcpClient = new Client();
    tcpClient.new SocketThread().start();
    logger.info("tcp client started!");
}
public void SendTcp(String msg)
{
    try{
        tcpClient.os.write(msg.getBytes("utf8"));
        tcpClient.os.flush();
    }
    catch (Exception e)
    {
        logger.info("tcp send failed!"+msg);
        //e.printStackTrace();
        System.out.println("heartbeat send error");
        try {
            tcpClient.socket.close();
            tcpClient.is.close();
            tcpClient.os.close();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }
}

sponge插件开启新线程貌似没什么限制,感觉上和之前写bukkit接口的插件有一些不同,之前都不敢开线程的

启动后直接调用开启这个线程就行了:

@Listener//服务器启动
public void onServerStart(GameStartedServerEvent event) {
    StartServer();
    logger.info("chat connector plugin start!");
}

c#服务端

c#服务端我直接用了SimpleTCP的库

namespace Native.Csharp.App.LuaEnv
{
    class TcpServer
    {
        private static SimpleTcpServer server = new SimpleTcpServer();
        public static void Start()
        {
            try
            {
                server.StringEncoder = Encoding.UTF8;
                server.Start(23333);
                Common.CqApi.AddLoger(Sdk.Cqp.Enum.LogerLevel.Info, "tcp server",
                    "tcp server started!");
                server.DataReceived += (sender, msg) => {
                    //msg.Reply("Content-Type: text/plain\n\nHello from my web server!");
                    LuaEnv.RunLua(
                        $"message=[[{msg.MessageString.Replace("]", "] ")}]] ",
                        "envent/ReceiveTcp.lua");
                };
            }
            catch(Exception e)
            {
                Common.CqApi.AddLoger(Sdk.Cqp.Enum.LogerLevel.Error, "tcp server", 
                    "tcp server start failed!\r\n"+e.ToString());
            }
        }

        public static void Send(string msg)
        {
            try
            {
                server.Broadcast(msg);
            }
            catch (Exception e)
            {
                Common.CqApi.AddLoger(Sdk.Cqp.Enum.LogerLevel.Error, "tcp server",
                    "tcp server send failed!\r\n" + e.ToString());
            }
        }
    }
}

上面那段代码,在收到socket信息后,直接就推给lua脚本了,后面的信息处理就很随意了

效果

效果怎么说呢,也就那样吧,没什么功能

项目地址

sponge端:https://github.com/chenxuuu/chat-connecter

C#端:https://github.com/chenxuuu/receiver-meow

发表评论

电子邮件地址不会被公开。 必填项已用*标注