如何从 Unity 连接到数据库
How to connect to database from Unity
我正在尝试通过 Unity 连接到 MS SQL 数据库。但是,当我尝试打开连接时,出现 IOException: Connection lost.
我从 Unity\Editor\Data\Mono\lib\mono.0 导入了 System.Data.dll。我正在使用以下代码:
using UnityEngine;
using System.Collections;
using System.Data.Sql;
using System.Data.SqlClient;
public class SQL_Controller : MonoBehaviour {
string conString = "Server=myaddress.com,port;" +
"Database=databasename;" +
"User ID=username;" +
"Password=password;";
public string GetStringFromSQL()
{
LoadConfig();
string result = "";
SqlConnection connection = new SqlConnection(conString);
connection.Open();
Debug.Log(connection.State);
SqlCommand Command = connection.CreateCommand();
Command.CommandText = "select * from Artykuly2";
SqlDataReader ThisReader = Command.ExecuteReader();
while (ThisReader.Read())
{
result = ThisReader.GetString(0);
}
ThisReader.Close();
connection.Close();
return result;
}
}
这是我得到的错误:
IOException: Connection lost
Mono.Data.Tds.Protocol.TdsComm.GetPhysicalPacketHeader ()
Mono.Data.Tds.Protocol.TdsComm.GetPhysicalPacket ()
Mono.Data.Tds.Protocol.TdsComm.GetByte ()
Mono.Data.Tds.Protocol.Tds.ProcessSubPacket ()
Mono.Data.Tds.Protocol.Tds.NextResult ()
Mono.Data.Tds.Protocol.Tds.SkipToEnd ()
Rethrow as TdsInternalException: Server closed the connection.
Mono.Data.Tds.Protocol.Tds.SkipToEnd ()
Mono.Data.Tds.Protocol.Tds70.Connect (Mono.Data.Tds.Protocol.TdsConnectionParameters connectionParameters)
Mono.Data.Tds.Protocol.Tds80.Connect (Mono.Data.Tds.Protocol.TdsConnectionParameters connectionParameters)
请忽略此方法的任何安全风险,我需要这样做进行测试,安全性稍后会出现。
谢谢你的时间。
Please disregard any security risks with this approach
不要这样。安全是在之前还是之后来并不重要。您将结束重写整个代码,因为 密码 在您的应用程序中是硬编码的,可以 轻松地 反编译和检索。现在以正确的方式进行连接,这样您就不必重新编写整个应用程序。
运行 您的服务器上的数据库命令可以使用 php、perl 或任何您熟悉的语言,但这应该在服务器上完成。
在 Unity 中,使用 WWW
or UnityWebRequest
class to communicate with that script and then, you will be able to send and receive information from Unity to the server. There are many examples out there。即使这样,您仍然需要实现自己的安全性,但这比您现在拥有的要好得多。
您还可以使用 json 接收多个数据。
下面是来自 this Unity wiki 的完整示例。它展示了如何在服务器端使用 php 并在客户端使用 Unity + C# 在 Unity 中与数据库交互。
服务器端:
用 PDO 添加分数:
<?php
// Configuration
$hostname = 'localhot';
$username = 'yourusername';
$password = 'yourpassword';
$database = 'yourdatabase';
$secretKey = "mySecretKey"; // Change this value to match the value stored in the client javascript below
try {
$dbh = new PDO('mysql:host='. $hostname .';dbname='. $database, $username, $password);
} catch(PDOException $e) {
echo '<h1>An error has ocurred.</h1><pre>', $e->getMessage() ,'</pre>';
}
$realHash = md5($_GET['name'] . $_GET['score'] . $secretKey);
if($realHash == $hash) {
$sth = $dbh->prepare('INSERT INTO scores VALUES (null, :name, :score)');
try {
$sth->execute($_GET);
} catch(Exception $e) {
echo '<h1>An error has ocurred.</h1><pre>', $e->getMessage() ,'</pre>';
}
}
?>
使用 PDO 检索分数:
<?php
// Configuration
$hostname = 'localhost';
$username = 'yourusername';
$password = 'yourpassword';
$database = 'yourdatabase';
try {
$dbh = new PDO('mysql:host='. $hostname .';dbname='. $database, $username, $password);
} catch(PDOException $e) {
echo '<h1>An error has occurred.</h1><pre>', $e->getMessage() ,'</pre>';
}
$sth = $dbh->query('SELECT * FROM scores ORDER BY score DESC LIMIT 5');
$sth->setFetchMode(PDO::FETCH_ASSOC);
$result = $sth->fetchAll();
if(count($result) > 0) {
foreach($result as $r) {
echo $r['name'], "\t", $r['score'], "\n";
}
}
?>
在服务器上启用跨域策略:
此文件应命名为 "crossdomain.xml" 并放置在您的网络服务器的根目录中。 Unity 要求您要通过 WWW 请求访问的网站具有跨域策略。
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*"/>
</cross-domain-policy>
Client/Unity边:
Unity 的客户端代码连接到服务器,与 PDO 交互并根据调用的函数添加或检索分数。此客户端代码稍作修改以使用最新的 Unity 版本进行编译。
private string secretKey = "mySecretKey"; // Edit this value and make sure it's the same as the one stored on the server
public string addScoreURL = "http://localhost/unity_test/addscore.php?"; //be sure to add a ? to your url
public string highscoreURL = "http://localhost/unity_test/display.php";
//Text to display the result on
public Text statusText;
void Start()
{
StartCoroutine(GetScores());
}
// remember to use StartCoroutine when calling this function!
IEnumerator PostScores(string name, int score)
{
//This connects to a server side php script that will add the name and score to a MySQL DB.
// Supply it with a string representing the players name and the players score.
string hash = Md5Sum(name + score + secretKey);
string post_url = addScoreURL + "name=" + WWW.EscapeURL(name) + "&score=" + score + "&hash=" + hash;
// Post the URL to the site and create a download object to get the result.
WWW hs_post = new WWW(post_url);
yield return hs_post; // Wait until the download is done
if (hs_post.error != null)
{
print("There was an error posting the high score: " + hs_post.error);
}
}
// Get the scores from the MySQL DB to display in a GUIText.
// remember to use StartCoroutine when calling this function!
IEnumerator GetScores()
{
statusText.text = "Loading Scores";
WWW hs_get = new WWW(highscoreURL);
yield return hs_get;
if (hs_get.error != null)
{
print("There was an error getting the high score: " + hs_get.error);
}
else
{
statusText.text = hs_get.text; // this is a GUIText that will display the scores in game.
}
}
public string Md5Sum(string strToEncrypt)
{
System.Text.UTF8Encoding ue = new System.Text.UTF8Encoding();
byte[] bytes = ue.GetBytes(strToEncrypt);
// encrypt bytes
System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] hashBytes = md5.ComputeHash(bytes);
// Convert the encrypted bytes back to a string (base 16)
string hashString = "";
for (int i = 0; i < hashBytes.Length; i++)
{
hashString += System.Convert.ToString(hashBytes[i], 16).PadLeft(2, '0');
}
return hashString.PadLeft(32, '0');
}
这只是一个关于如何正确执行此操作的示例。如果您需要实现会话功能并关心安全性,请查看 OAuth 2.0 协议。应该有现有的库可以帮助开始使用 OAuth 协议。
另一种方法是在命令提示符下创建您自己的专用服务器以进行通信并将其连接到统一的 Handel 多人游戏和 SQL 通信。这样你就可以坚持使用一种语言创建它。但是学习曲线相当陡峭。
Unity 是游戏引擎。
所以答案是这样的。
但是,有些域需要直接连接数据库。
你不应该直接在游戏域中访问数据库。
无论如何,问题是由 NON-ENGLISH 计算机名称引起的。
我在之前的项目中遇到了以下错误。
IOException: Connection lost
Mono.Data.Tds.Protocol.TdsComm.GetPhysicalPacketHeader ()
Mono.Data.Tds.Protocol.TdsComm.GetPhysicalPacket ()
Mono.Data.Tds.Protocol.TdsComm.GetByte ()
Mono.Data.Tds.Protocol.Tds.ProcessSubPacket ()
Mono.Data.Tds.Protocol.Tds.NextResult ()
Mono.Data.Tds.Protocol.Tds.SkipToEnd ()
Rethrow as TdsInternalException: Server closed the connection.
Mono.Data.Tds.Protocol.Tds.SkipToEnd ()
Mono.Data.Tds.Protocol.Tds70.Connect (Mono.Data.Tds.Protocol.TdsConnectionParameters connectionParameters)
Mono.Data.Tds.Protocol.Tds80.Connect (Mono.Data.Tds.Protocol.TdsConnectionParameters connectionParameters)
并且将计算机名称更改为 ENGLISH 后,它起作用了。
不知道怎么样了。但它有效。
Mono 的 System.Data.dll 在 P.C 中有一些问题 NON-ENGLISH 计算机名称。
所以,至少是 Unity 项目。
您应该告诉您的客户不要将他们的计算机名称设置为 NON-ENGLISH。
我不知道单声道的人是否知道这些问题。
------------ 2018以后版本就可以了---------
Api 兼容级别 > .Net 4.x
您可以在 Non-english 计算机名称机器上连接数据库。
我正在尝试通过 Unity 连接到 MS SQL 数据库。但是,当我尝试打开连接时,出现 IOException: Connection lost.
我从 Unity\Editor\Data\Mono\lib\mono.0 导入了 System.Data.dll。我正在使用以下代码:
using UnityEngine;
using System.Collections;
using System.Data.Sql;
using System.Data.SqlClient;
public class SQL_Controller : MonoBehaviour {
string conString = "Server=myaddress.com,port;" +
"Database=databasename;" +
"User ID=username;" +
"Password=password;";
public string GetStringFromSQL()
{
LoadConfig();
string result = "";
SqlConnection connection = new SqlConnection(conString);
connection.Open();
Debug.Log(connection.State);
SqlCommand Command = connection.CreateCommand();
Command.CommandText = "select * from Artykuly2";
SqlDataReader ThisReader = Command.ExecuteReader();
while (ThisReader.Read())
{
result = ThisReader.GetString(0);
}
ThisReader.Close();
connection.Close();
return result;
}
}
这是我得到的错误:
IOException: Connection lost
Mono.Data.Tds.Protocol.TdsComm.GetPhysicalPacketHeader ()
Mono.Data.Tds.Protocol.TdsComm.GetPhysicalPacket ()
Mono.Data.Tds.Protocol.TdsComm.GetByte ()
Mono.Data.Tds.Protocol.Tds.ProcessSubPacket ()
Mono.Data.Tds.Protocol.Tds.NextResult ()
Mono.Data.Tds.Protocol.Tds.SkipToEnd ()
Rethrow as TdsInternalException: Server closed the connection.
Mono.Data.Tds.Protocol.Tds.SkipToEnd ()
Mono.Data.Tds.Protocol.Tds70.Connect (Mono.Data.Tds.Protocol.TdsConnectionParameters connectionParameters)
Mono.Data.Tds.Protocol.Tds80.Connect (Mono.Data.Tds.Protocol.TdsConnectionParameters connectionParameters)
请忽略此方法的任何安全风险,我需要这样做进行测试,安全性稍后会出现。 谢谢你的时间。
Please disregard any security risks with this approach
不要这样。安全是在之前还是之后来并不重要。您将结束重写整个代码,因为 密码 在您的应用程序中是硬编码的,可以 轻松地 反编译和检索。现在以正确的方式进行连接,这样您就不必重新编写整个应用程序。
运行 您的服务器上的数据库命令可以使用 php、perl 或任何您熟悉的语言,但这应该在服务器上完成。
在 Unity 中,使用 WWW
or UnityWebRequest
class to communicate with that script and then, you will be able to send and receive information from Unity to the server. There are many examples out there。即使这样,您仍然需要实现自己的安全性,但这比您现在拥有的要好得多。
您还可以使用 json 接收多个数据。
下面是来自 this Unity wiki 的完整示例。它展示了如何在服务器端使用 php 并在客户端使用 Unity + C# 在 Unity 中与数据库交互。
服务器端:
用 PDO 添加分数:
<?php
// Configuration
$hostname = 'localhot';
$username = 'yourusername';
$password = 'yourpassword';
$database = 'yourdatabase';
$secretKey = "mySecretKey"; // Change this value to match the value stored in the client javascript below
try {
$dbh = new PDO('mysql:host='. $hostname .';dbname='. $database, $username, $password);
} catch(PDOException $e) {
echo '<h1>An error has ocurred.</h1><pre>', $e->getMessage() ,'</pre>';
}
$realHash = md5($_GET['name'] . $_GET['score'] . $secretKey);
if($realHash == $hash) {
$sth = $dbh->prepare('INSERT INTO scores VALUES (null, :name, :score)');
try {
$sth->execute($_GET);
} catch(Exception $e) {
echo '<h1>An error has ocurred.</h1><pre>', $e->getMessage() ,'</pre>';
}
}
?>
使用 PDO 检索分数:
<?php
// Configuration
$hostname = 'localhost';
$username = 'yourusername';
$password = 'yourpassword';
$database = 'yourdatabase';
try {
$dbh = new PDO('mysql:host='. $hostname .';dbname='. $database, $username, $password);
} catch(PDOException $e) {
echo '<h1>An error has occurred.</h1><pre>', $e->getMessage() ,'</pre>';
}
$sth = $dbh->query('SELECT * FROM scores ORDER BY score DESC LIMIT 5');
$sth->setFetchMode(PDO::FETCH_ASSOC);
$result = $sth->fetchAll();
if(count($result) > 0) {
foreach($result as $r) {
echo $r['name'], "\t", $r['score'], "\n";
}
}
?>
在服务器上启用跨域策略:
此文件应命名为 "crossdomain.xml" 并放置在您的网络服务器的根目录中。 Unity 要求您要通过 WWW 请求访问的网站具有跨域策略。
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*"/>
</cross-domain-policy>
Client/Unity边:
Unity 的客户端代码连接到服务器,与 PDO 交互并根据调用的函数添加或检索分数。此客户端代码稍作修改以使用最新的 Unity 版本进行编译。
private string secretKey = "mySecretKey"; // Edit this value and make sure it's the same as the one stored on the server
public string addScoreURL = "http://localhost/unity_test/addscore.php?"; //be sure to add a ? to your url
public string highscoreURL = "http://localhost/unity_test/display.php";
//Text to display the result on
public Text statusText;
void Start()
{
StartCoroutine(GetScores());
}
// remember to use StartCoroutine when calling this function!
IEnumerator PostScores(string name, int score)
{
//This connects to a server side php script that will add the name and score to a MySQL DB.
// Supply it with a string representing the players name and the players score.
string hash = Md5Sum(name + score + secretKey);
string post_url = addScoreURL + "name=" + WWW.EscapeURL(name) + "&score=" + score + "&hash=" + hash;
// Post the URL to the site and create a download object to get the result.
WWW hs_post = new WWW(post_url);
yield return hs_post; // Wait until the download is done
if (hs_post.error != null)
{
print("There was an error posting the high score: " + hs_post.error);
}
}
// Get the scores from the MySQL DB to display in a GUIText.
// remember to use StartCoroutine when calling this function!
IEnumerator GetScores()
{
statusText.text = "Loading Scores";
WWW hs_get = new WWW(highscoreURL);
yield return hs_get;
if (hs_get.error != null)
{
print("There was an error getting the high score: " + hs_get.error);
}
else
{
statusText.text = hs_get.text; // this is a GUIText that will display the scores in game.
}
}
public string Md5Sum(string strToEncrypt)
{
System.Text.UTF8Encoding ue = new System.Text.UTF8Encoding();
byte[] bytes = ue.GetBytes(strToEncrypt);
// encrypt bytes
System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] hashBytes = md5.ComputeHash(bytes);
// Convert the encrypted bytes back to a string (base 16)
string hashString = "";
for (int i = 0; i < hashBytes.Length; i++)
{
hashString += System.Convert.ToString(hashBytes[i], 16).PadLeft(2, '0');
}
return hashString.PadLeft(32, '0');
}
这只是一个关于如何正确执行此操作的示例。如果您需要实现会话功能并关心安全性,请查看 OAuth 2.0 协议。应该有现有的库可以帮助开始使用 OAuth 协议。
另一种方法是在命令提示符下创建您自己的专用服务器以进行通信并将其连接到统一的 Handel 多人游戏和 SQL 通信。这样你就可以坚持使用一种语言创建它。但是学习曲线相当陡峭。
Unity 是游戏引擎。
所以答案是这样的。
但是,有些域需要直接连接数据库。
你不应该直接在游戏域中访问数据库。
无论如何,问题是由 NON-ENGLISH 计算机名称引起的。
我在之前的项目中遇到了以下错误。
IOException: Connection lost
Mono.Data.Tds.Protocol.TdsComm.GetPhysicalPacketHeader ()
Mono.Data.Tds.Protocol.TdsComm.GetPhysicalPacket ()
Mono.Data.Tds.Protocol.TdsComm.GetByte ()
Mono.Data.Tds.Protocol.Tds.ProcessSubPacket ()
Mono.Data.Tds.Protocol.Tds.NextResult ()
Mono.Data.Tds.Protocol.Tds.SkipToEnd ()
Rethrow as TdsInternalException: Server closed the connection.
Mono.Data.Tds.Protocol.Tds.SkipToEnd ()
Mono.Data.Tds.Protocol.Tds70.Connect (Mono.Data.Tds.Protocol.TdsConnectionParameters connectionParameters)
Mono.Data.Tds.Protocol.Tds80.Connect (Mono.Data.Tds.Protocol.TdsConnectionParameters connectionParameters)
并且将计算机名称更改为 ENGLISH 后,它起作用了。
不知道怎么样了。但它有效。
Mono 的 System.Data.dll 在 P.C 中有一些问题 NON-ENGLISH 计算机名称。
所以,至少是 Unity 项目。
您应该告诉您的客户不要将他们的计算机名称设置为 NON-ENGLISH。
我不知道单声道的人是否知道这些问题。
------------ 2018以后版本就可以了---------
Api 兼容级别 > .Net 4.x
您可以在 Non-english 计算机名称机器上连接数据库。