You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过PuTTY调用运行中Unity Linux无头服务器内部的C#公开函数?

如何通过PuTTY调用运行中Unity Linux无头服务器内部的C#公开函数?

首先明确一点:直接通过Linux命令调用已经运行的Unity服务器进程内部的C#公开函数是做不到的——因为Linux系统命令和Unity的C#运行时是完全独立的执行上下文,没有原生的系统命令能直接“穿透”到进程内部调用函数。你之前设想的./ServerLinux.x86_64 -call command只会启动一个新的服务器进程,而不是给正在运行的进程发指令。

不过我们可以通过「进程间通信(IPC)」的方式,让Unity服务器主动监听外部指令,当你在PuTTY里执行特定命令时,触发服务器内部的MyFunction()。下面给你几个适合Unity Linux无头服务器的可行方案:

方案1:监控本地指令文件(最简单易实现)

这个思路是让Unity服务器定期检查一个指定的本地文件,当你在PuTTY里往这个文件写入命令内容时,Unity检测到后就执行对应的函数。

Unity C#代码修改

在你的Server脚本中添加文件监控逻辑:

using System.IO;
using UnityEngine;
using System.Collections;

public class Server : MonoBehaviour
{
    // 指定要监控的命令文件路径(Linux下建议放在/tmp目录,无需权限)
    private readonly string _commandFilePath = "/tmp/unity_server_cmd.txt";

    void Start()
    {
        StartCoroutine(StartChecking());
        // 启动命令监控协程
        StartCoroutine(CheckForExternalCommands());
    }

    // 你要触发的目标函数
    public void MyFunction()
    {
        Debug.Log("✅ 成功执行MyFunction!");
        // 这里写你的函数逻辑
    }

    // 定期检查命令文件
    private IEnumerator CheckForExternalCommands()
    {
        while (true)
        {
            if (File.Exists(_commandFilePath))
            {
                // 读取命令并去除多余空白符
                string command = File.ReadAllText(_commandFilePath).Trim();
                if (!string.IsNullOrEmpty(command))
                {
                    ProcessExternalCommand(command);
                    // 执行后清空文件,避免重复触发
                    File.WriteAllText(_commandFilePath, string.Empty);
                }
            }
            // 每3秒检查一次,可根据需求调整间隔
            yield return new WaitForSeconds(3f);
        }
    }

    // 根据命令执行对应逻辑
    private void ProcessExternalCommand(string command)
    {
        switch (command)
        {
            case "run_myfunction":
                MyFunction();
                break;
            case "toggle_boolean":
                someBoolean = !someBoolean;
                Debug.Log($"someBoolean已切换为:{someBoolean}");
                break;
            // 可以扩展更多命令
        }
    }

    // 你的原有代码
    public bool someBoolean = false;
    public IEnumerator StartChecking()
    {
        while (true)
        {
            // 你的原有轮询逻辑
            yield return new WaitForSeconds(60.0f);
        }
    }
}

PuTTY中执行的命令

当服务器运行后,在PuTTY里执行以下命令即可触发MyFunction():

echo "run_myfunction" > /tmp/unity_server_cmd.txt

方案2:使用本地Unix Socket(更可靠的实时通信)

如果需要更低延迟、更可靠的指令触发,可以用Linux的Unix Domain Socket,让Unity作为Socket服务器监听本地连接,你用PuTTY的nc命令发送指令。

Unity C#代码修改

需要添加Socket监听逻辑,同时要注意Unity API必须在主线程执行,所以需要一个主线程调度器:

1. 先添加主线程调度器脚本

创建一个新的UnityMainThreadDispatcher脚本,用来把Socket回调的逻辑切回主线程:

using System;
using System.Collections.Generic;
using UnityEngine;

public class UnityMainThreadDispatcher : MonoBehaviour
{
    public static UnityMainThreadDispatcher Instance { get; private set; }
    private readonly Queue<Action> _pendingActions = new Queue<Action>();

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }

    private void Update()
    {
        lock (_pendingActions)
        {
            while (_pendingActions.Count > 0)
            {
                _pendingActions.Dequeue()?.Invoke();
            }
        }
    }

    public void Enqueue(Action action)
    {
        lock (_pendingActions)
        {
            _pendingActions.Enqueue(action);
        }
    }
}

2. 修改Server脚本添加Socket监听

using System;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
using System.Collections;

public class Server : MonoBehaviour
{
    private Socket _commandSocket;
    // Socket文件路径,建议放在/tmp目录
    private readonly string _socketPath = "/tmp/unity_server_socket";

    void Start()
    {
        StartCoroutine(StartChecking());
        // 初始化命令Socket
        SetupCommandSocket();
    }

    public void MyFunction()
    {
        Debug.Log("✅ 通过Socket触发MyFunction!");
        // 你的函数逻辑
    }

    // 初始化Unix Socket服务器
    private void SetupCommandSocket()
    {
        // 如果Socket文件已存在,先删除避免绑定失败
        if (File.Exists(_socketPath))
        {
            File.Delete(_socketPath);
        }

        // 创建Unix Domain Socket
        _commandSocket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP);
        _commandSocket.Bind(new UnixDomainSocketEndPoint(_socketPath));
        _commandSocket.Listen(1);
        // 开始异步监听连接
        _commandSocket.BeginAccept(OnSocketConnected, null);
    }

    // 当有客户端连接时处理指令
    private void OnSocketConnected(IAsyncResult ar)
    {
        try
        {
            using (Socket clientSocket = _commandSocket.EndAccept(ar))
            {
                byte[] buffer = new byte[1024];
                int bytesRead = clientSocket.Receive(buffer);
                string command = Encoding.UTF8.GetString(buffer, 0, bytesRead).Trim();
                // 切回主线程执行Unity逻辑
                UnityMainThreadDispatcher.Instance.Enqueue(() => ProcessExternalCommand(command));
            }
        }
        catch (Exception e)
        {
            Debug.LogError($"Socket错误:{e.Message}");
        }
        // 继续监听下一个连接
        _commandSocket.BeginAccept(OnSocketConnected, null);
    }

    private void ProcessExternalCommand(string command)
    {
        switch (command)
        {
            case "run_myfunction":
                MyFunction();
                break;
            // 扩展其他命令
        }
    }

    // 服务器关闭时清理Socket
    private void OnDestroy()
    {
        _commandSocket?.Close();
        if (File.Exists(_socketPath))
        {
            File.Delete(_socketPath);
        }
    }

    // 你的原有代码
    public bool someBoolean = false;
    public IEnumerator StartChecking()
    {
        while (true)
        {
            yield return new WaitForSeconds(60.0f);
        }
    }
}

PuTTY中执行的命令

确保你的VPS安装了netcat(如果没装,执行sudo apt install netcat-openbsd),然后发送指令:

echo "run_myfunction" | nc -U /tmp/unity_server_socket

方案3:使用Linux自定义信号(轻量级触发)

Linux允许给进程发送自定义信号,我们可以让Unity监听SIGUSR1或SIGUSR2信号,当收到信号时执行目标函数。

Unity C#代码修改

using System;
using System.Runtime.InteropServices;
using UnityEngine;
using System.Collections;

public class Server : MonoBehaviour
{
    // 调用Linux的libc库注册信号处理
    [DllImport("libc")]
    private static extern void signal(int sig, Action handler);

    // Linux下SIGUSR1的信号编号
    private const int SIGUSR1 = 10;

    void Start()
    {
        StartCoroutine(StartChecking());
        // 注册SIGUSR1信号的处理函数
        signal(SIGUSR1, OnReceivedCustomSignal);
    }

    public void MyFunction()
    {
        Debug.Log("✅ 通过Linux信号触发MyFunction!");
        // 你的函数逻辑
    }

    // 信号回调函数(注意:此函数在子线程执行)
    private void OnReceivedCustomSignal()
    {
        // 切回主线程执行Unity逻辑
        UnityMainThreadDispatcher.Instance.Enqueue(() => MyFunction());
    }

    // 你的原有代码
    public bool someBoolean = false;
    public IEnumerator StartChecking()
    {
        while (true)
        {
            yield return new WaitForSeconds(60.0f);
        }
    }
}

PuTTY中执行的命令

  1. 先找到Unity服务器的进程ID:
pgrep ServerLinux.x86_64
  1. 给该进程发送SIGUSR1信号:
kill -SIGUSR1 <进程ID>

比如进程ID是1234,就执行kill -SIGUSR1 1234。

总结

所有方案的核心逻辑都是:让Unity服务器主动监听外部的触发信号/指令,而不是试图用Linux命令直接“调用”内部函数——因为两者属于完全独立的执行环境,没有直接调用的通道。

你可以根据自己的需求选择方案:

  • 如果你需要简单易实现,选方案1(文件监控);
  • 如果你需要低延迟、实时性高的触发,选方案2(Socket通信);
  • 如果你需要轻量级、无文件残留的触发,选方案3(Linux信号)。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 13:00:31