最近在做一个项目,主体是Unity。项目涉及到一些大规模数值计算,需要借助服务器来完成。所以我们需要设计一个通信系统,包含以下过程。
1.Unity客户端向服务器发送计算命令
2.服务器调用后台进程进行数值计算
3.服务器通知Unity客户端计算完成
4.Unity客户端从服务器读取计算结果
为了实现该系统,我们需要这些东西
1.一台终端Windows计算机,安装了Unity,作为客户端。
2.一台Linux计算机,搭建了服务器环境,作为后台计算。
将Linux计算机搭建为服务器的方法请参考:
搭建基于阿里云服务器的网站
搭建好环境后,接下来开始系统实现。
这部分主要使用了UnityWebRequest功能,该模块可以很好地实现上传文件到服务器以及从服务器下载数据的需求,下面给出了测试代码。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using System.Text;
public class CS_communication_test : MonoBehaviour
{
public string url_PHP = "http://x.x.x.x/CS_test/CS.php";
public string url_download = "http://x.x.x.x/CS_test/result.txt";
// Start is called before the first frame update
void Start()
{
StartCoroutine(CS_work(100));
}
IEnumerator CS_work(int num)
{
//测试功能:使用服务器将一个整数×100,打印计算结果
//第一部分:上传数据到服务器,等待服务器处理完成
byte[] bytes = Encoding.Default.GetBytes(num.ToString());
WWWForm form = new WWWForm();//创建提交数据表单
form.AddField("folder", "UploadData/");//定义表单字段用来定义文件夹
form.AddBinaryData("file", bytes, "uploadData.txt", "text/plain");//字段名,文件数据,文件名,文件类型
UnityWebRequest uploadRequest = UnityWebRequest.Post(url_PHP, form);
yield return uploadRequest.SendWebRequest();
if (uploadRequest.isDone)
{
Debug.Log("服务器已完成计算");
}
//第二部分:从服务器获取计算结果
UnityWebRequest downloadRequest = UnityWebRequest.Get(url_download);
yield return downloadRequest.SendWebRequest();
if (downloadRequest.isDone)
{
Debug.Log(downloadRequest.downloadHandler.text);
}
}
}
我们使用Python来编写计算进程,用PHP作为Web中间交互,用Linux的命名管道实现PHP与Python的进程通信。
1.实验环境设置
我们来到网站的根目录下
如果按照上述博客搭建服务器的话,地址是/var/www/html
创建实验文件夹,并设置权限
mkdir CS_test
chmod 777 CS_test
进入文件夹,创建命名管道文件
cd CS_test
mkfifo -m 777 php2py # 保存php进程向python进程传递的数据
mkfifo -m 777 py2php # 保存python进程向php进程传递的数据
创建文件夹,用来保存上传的数据,记得设置权限
mkdir UploadData
chmod 777 UploadData
分别创建一个python文件和一个php文件
touch CS.py
touch CS.php
目前实验文件夹下有这些东西
[root@iZwz9a8g2mt6x5kq9jp6abZ CS_test]# ls
CS.php CS.py php2py py2php UploadData
2.python文件编写
这部分的功能是数值计算,将php2py管道中的原始数据读出,计算后将结果写入py2php管道。
def work(rawData):
print("input number: " + rawData)
resultData = str(int(rawData) * 100)
print("output number: " + resultData)
return resultData
while True:
fread = open("php2py", "r")
fwrite = open("py2php", "w")
rawData = fread.read(1024)
resultData = work(rawData)
fwrite.write(resultData)
fwrite.close()
fread.close()
3.php文件编写
这部分的功能是
1.接收Unity客户端的调用,将其上传的数据写入文件
2.数据写入php2py管道
3.从py2php管道读出计算结果
4.将结果写进文件
$folder=$_POST["folder"];//根据表单字段接收文件夹的字符串信息
$fileName =$_FILES["file"]["name"];//根据表单字段接收需要保存的文件名字
$tmp=$_FILES["file"]["tmp_name"];
$fil=$folder.$fileName;
// 判断当期目录下的 upload 目录是否存在该文件
if (!file_exists($fil))
{
// 如果 upload 目录不存在该文件则将文件上传到相应目录下
move_uploaded_file($_FILES["file"]["tmp_name"], $fil);
}
//将数据写入管道
function write($content)
{
$fwrite = fopen("php2py", "w");
fwrite($fwrite, $content);
fclose($fwrite);
}
//将数据从管道读出
function read()
{
$fread = fopen("py2php", "r");
$content = fread($fread, 1024);
fclose($fread);
return $content;
}
//读出上传的数据,并写入管道
$dataStr = file_get_contents("UploadData/uploadData.txt");
$data = number_format($dataStr);
write($data);
//从管道读出计算结果
$resultData = read();
//将计算结果写入结果文件
$writeFile = fopen("result.txt","w");
fwrite($writeFile,$resultData);
fclose($writeFile)
?>
完成上述任务后,我们开始实验测试。
1.在服务器中启动python进程
python CS.py
2.在Unity中将脚本挂在一个场景物体上,并运行测试
服务器端结果
input number: 100
output number: 10000
最后记得将Python进程中断。