I am trying to connect to a MS SQL database through Unity. However, when I try to open a connection, I get an IOException: Connection lost.
I have imported System.Data.dll from Unity\Editor\Data\Mono\lib\mono\2.0. I am using the following code:
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;
}
}
This is the error I get:
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, I NEED to do this for testing, security will come later.
Thank you for your time.
Please disregard any security risks with this approach
Do not do it like this. It doesn't matter if security will come before or after. You will end of re-writing the whole code because the password is hard-coded in your application which can be decompiled and retrieved easily. Do the connection the correct way now so that you won't have to re-write the whole application.
Run your database command on your server with php, perl or whatever language you are comfortable with but this should be done on the server.
From Unity, use the 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. Even with this, you still need to implement your own security but this is much more better than what you have now.
You can also receive data multiple with json.
Below is a complete example from this Unity wiki. It shows how to interact with a database in Unity using php on the server side and Unity + C# on the client side.
Server Side:
Add score with 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>';
}
}
?>
Retrieve score with 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";
}
}
?>
Enable cross domain policy on the server:
This file should be named "crossdomain.xml" and placed in the root of your web server. Unity requires that websites you want to access via a WWW Request have a cross domain policy.
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*"/>
</cross-domain-policy>
Client/Unity Side:
The client code from Unity connects to the server, interacts with PDO and adds or retrieves score depending on which function is called. This client code is slightly modified to compile with the latest Unity version.
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');
}
This is just an example on how to properly do this. If you need to implement session feature and care about security, look into the OAuth 2.0 protocol. There should be existing libraries that will help get started with the OAuth protocol.
An alternative would be to create your own dedicated server in a command prompt to do your communication and connecting it to unity to Handel multiplayer and SQL communication. This way you can stick with it all being created in one language. But a pretty steep learning curve.
Unity is game engine.
so That's right what the answer says.
but, Some domains need to connect database directly.
You shouldn't do that access database directly in game domain.
Anyway, The problem is caused by NON-ENGLISH computer name.
I faced sort of following errors at before project.
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)
And after changing computer name as ENGLISH, It works.
I don't know how it's going. But It works.
Mono's System.Data.dll has some issues in P.C has NON-ENGLISH Computer name.
So, at least Unity project.
You should tell your customer Do not set their computer name as NON-ENGLISH.
I don't know people in mono knows these issue or not.
---------- It's OK in after 2018 version ----------
Api Compatibility Level > .Net 4.x
You can connect database in Non-english computer name machine.
Related
I have a .net core web api that I am trying to deploy to AWS Lambda / API Gateway. I get a bland error "Unable to connect to any of the specified MySQL hosts".
My API has 2 endpoints for testing. They are /TestConnect and /TestAWS. The /TestConnect endpoint works properly (returns a "success" string) so I know that the Web Api has deployed properly. The /TestAWS endpoint is just supposed to return the first row of a table. That code is below, but it's pretty straightforward. I know that this isn't best practice, but I used it to test in order to try and eliminate all of the other possibilities.
[HttpGet("TestAWS")]
public IActionResult TestAWS()
{
try
{
string dataString = "";
MySqlConnectionStringBuilder cnString = new MySqlConnectionStringBuilder();
cnString.Server = Environment.GetEnvironmentVariable("DB_ENDPOINT");
cnString.UserID = Environment.GetEnvironmentVariable("USER");
cnString.Password = Environment.GetEnvironmentVariable("PASSWORD");
cnString.Database = Environment.GetEnvironmentVariable("DATABASE");
cnString.Port = Environment.GetEnvironmentVariable("PORT");;
using (MySqlConnection conn = new MySqlConnection(cnString.ToString()))
{
conn.Open();
MySqlCommand cmd = new MySqlCommand("SELECT UserName FROM Users LIMIT 1", conn);
using (MySqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
dataString = dr["userName"].ToString();
}
}
}
return Ok("Returned: " + dataString);
}
catch (Exception ex)
{
return BadRequest("Returned Date { Environmnet: " + Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") + "-" + ex.Message + "}");
}
}
To debug the problem, I created a second Lambda function directly in AWS. It's a really simple Node.js function that does the same thing as my API.
var mysql = require('mysql');
var config = require('./config.json');
var pool = mysql.createPool({
connectionLimit : 10,
host : config.dbhost,
user : config.dbuser,
password : config.dbpassword,
database : config.dbname
});
exports.handler = (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
pool.getConnection(function(err, connection) {
if (err) throw err; // not connected
connection.query('SELECT UserName FROM Users LIMIT 1', function (error, results, fields) {
connection.release();
if (error) callback(error);
else callback(null, results[0].UserName)
});
});
};
That function works properly and returns the row from the table.
Both functions have identical VPC settings. Same VPC, same subnets, same IAM role, same Security Group. That tells me that the AWS infrastructure is setup correctly and that there are no issues with the VPC, NACLs, etc.
I think that just leaves the C# code.
Do I have to make some changes to the Web Api in order for it to work? It almost seems like I have to add some Lambda-specific handling in the C# like I did in the working Lambda, but I can't find any references to that effect.
Any help is greatly appreciated.
From the comments: #Bradley Grainger
"Try switching from MySql.Data to nuget.org/packages/MySqlConnector,
it is a much more stable library with better .NET Core support."
I switched to that package and everything is working. I can't ultimately say that was the only problem since I re-created my entire VPC / subnet / db, etc. during this debugging process.
However, after I re-created the VPC, I ran my code with the MySql.Data library and it didn't work, then I switched to the MySqlConnnector library and it worked without error.
The library was at least part of the problem.
Building a Unity front-end app that communicates with a PHP/MySQL back-end. Right now I am working on the register and login portions of it. In the Unity editor, all works perfectly, on the browser front end registration is working fine as well. But as soon as I take the working build in Unity and build it to test on my Google Pixel phone, registration and login both fail on my phone. The error message I am getting on Login is "Error parsing response from server, please try again!" which is in my UILogin.cs. Yet there is nothing else attached. I tried following the Unity documentation for debugging, adb, and DDMS to get access to find out what is happening but I have failed on all those ventures. Is there something particularly different about Android and WWW objects or web communications? Here is a portion of my UILogin.cs and also will include the Login.php.
UILogin.cs
IEnumerator AttemptLogin(bool quickLogin)
{
CreateLoadingScreen();
DeactivateForm();
WWWForm form = new WWWForm();
form.AddField("email", Email.text);
form.AddField("password", Password.text);
WWW www = new WWW(URL.GetLoginURL, form);
yield return www;
DestroyLoadingScreen();
ActivateForm();
ParseResult(www.text, quickLogin);
}
void ParseResult(string result, bool quickLogin)
{
byte resultCode;
if (!byte.TryParse(result, out resultCode))
Result.text = "Error parsing response from server, please try again!";
else if (resultCode == 0)
{
if (RememberToggle.isOn && !quickLogin) // Remember me
{
PlayerPrefs.SetInt("remember", 1);
PlayerPrefs.SetString("email", Email.text);
PlayerPrefs.SetString("password", Password.text);
}
else if (!quickLogin)
{
TemporaryAccount.Email = Email.text;
TemporaryAccount.Password = Password.text;
}
SceneManager.LoadScene(3);
}
else // Failure
{
if (quickLogin)
ShowForm();
Result.text = WebError.GetLoginError(resultCode);
}
}
Login.php
<?php
require "conn.php";
$stmt = $pdo->prepare("SELECT * FROM account WHERE email=:email");
$stmt->bindParam(":email", $_POST['email']);
$stmt->execute();
$count = $stmt->rowCount(); // gets count of records found
if($count > 0) {
$result = $stmt->fetch(); // gets resultset
if(!password_verify($_POST['password'], $result[4]))
echo "2";
else
echo "0";
}
else {
echo "1";
}
?>
Any ideas?
Update #1
I printed www.text and www.error after the yield return www; Text is null and error says: Unknown Error.
Update #2
Interestingly enough, I get Unknown Error from this as well:
Clickme.cs
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class Clickme : MonoBehaviour
{
public Text Result;
public void OnClick()
{
StartCoroutine(RunScript());
}
IEnumerator RunScript()
{
WWW www = new WWW("http://www.familypolaris.com/helloWorld.php");
yield return www;
if (www.text == "")
Result.text = "Result was empty, error: " + www.error;
}
}
HelloWorld.php
<?php
echo "Hello World!";
?>
I figured it out, so I will post the answer here. After somebody commented that they tried my code and it worked just fine, I decided to try another device here. That device also failed to register and login. This told me something was wrong with my build settings. My first idea was to switch build type from Gradle to Internal, and that solved the problem for both my devices immediately.
This question already has answers here:
How to connect to database from Unity
(3 answers)
Closed 5 years ago.
I'm looking around for the easiest solution of how to connect to mysql database and for example, retrieve and update data. I've tried doing my research, but I couldn't find anything really. I mean, I would bet there's a simple way. I've worked with PHP before and I would think that its relatively easy to connect to database using C#.
Can anybody please show me a sample code of how to connect to mysql database? Also, how to retrieve and update data? Please and thank you!
I don't know what you mean by easy, but I've used www form.
Followed this tutorial series from youtube to begin.
In short; you will create www forms and send required data to php code. With the answer from php code you can do your tasks. I will try to provide an example.
Unity C# Login Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class LoginScript : MonoBehaviour {
public GameObject inputUsernameText;
public GameObject inputPasswordText;
public string inputUsername;
public string inputPassword;
public string userUsername;
public string userPassword;
public string[] userDataArray;
string loginURL ="YOUR LOGIN PHP CODE URL HERE" ;
public bool isLoginButtonPressed;
void Awake() {
DontDestroyOnLoad(transform.gameObject);
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (isLoginButtonPressed)
{
StartCoroutine(loginToDB (inputUsername, inputPassword));
isLoginButtonPressed = false;
}
}
IEnumerator loginToDB(string username, string password)
{
WWWForm form = new WWWForm();
form.AddField("usernamePost", username);
form.AddField("passwordPost", password);
WWW www = new WWW (loginURL, form);
yield return www;
//Debug.Log (www.text);
userDataArray = userEkipIDString.Split ('|');
userUsername = userDataArray [0];
userPassword = userDataArray [1];
isLoginButtonPressed = false;
SceneManager.LoadScene("MainMenuScene", LoadSceneMode.Single);
}
public void loginButtonPressedFunc()
{
inputUsername = inputUsernameText.GetComponent<Text> ().text.ToString ();
inputPassword = inputPasswordText.GetComponent<Text> ().text.ToString ();
isLoginButtonPressed = true;
}
}
What this script does is, it get a username and password from Unity's input field and send it to php code. If username and password is correct it loads another scene.
PHP Code
<?php
$servername = "YOUR HOST NAME ex:localhost";
$username = "YOUR DB USER NAME";
$password = "YOUR DB PASSWORD";
$dbName = "YOUR DB NAME";
$user_username = $_POST["usernamePost"];
$user_password = $_POST["passwordPost"];
//Make Connection
$conn = mysqli_connect($servername,$username,$password,$dbName);
//Check Connection
if(!$conn)
{
die("Connection Failed. " . mysqli_connect_error());
}
//else echo ("Connection Success.");
$sql ="Select user, pass from "YOUR TABLE NAME" where user = '".$user_username."' "; //You can write your own query here
$result = mysqli_query($conn,$sql);
//Get the result and confirm login
if(mysqli_num_rows($result)>0)
{
//show data for each row
while($row = mysqli_fetch_assoc($result))
{
if($row['pass'] == $user_password)
{
//echo "Login Success";
echo "".$row['user']."|".$row['pass']."" ;
}
else
{
echo "Wrong Password";
}
}
}
else
{
echo "User not found";
}
?>
You can adjust this logic to insert, update and delete
Hope this helps. Cheers!
I am trying to get data from my MySQL server to my Unity project. I tried to get the data like so:
public string awsurl = "ec2-174-129-82-141.compute-1.amazonaws.com/connect_to_server.php";
IEnumerator GetScores()
{
print("get scores start");
WWW aws_get = new WWW(awsurl);
yield return aws_get;
print("getscore here");
if (aws_get.error != null)
{
print("There was an error getting aws: " + aws_get.error);
}
else
{
print(aws_get.text); // this is a GUIText that will display the scores in game.
}
}
I have a php script on my server to handle the interaction because I am having trouble using the MySqlConnection library for my unity project.
Here is my php script:
$address = "localhost"
$dbusername = "root";
$dbpassword = "root";
$db_name = "watshoes";
$db_conn = new mysqli($address, $dbusername, $dbpassword, $db_name);
if(isset($_POST['username'])) $username = $_POST['username'];
if(isset($_POST['user_id'])) $user_id = $_POST['user_id'];
if(isset($password)) $password =$_POST['password'];
$stmt = $db_conn->prepare("SELECT image FROM ImageText");
// "s" means the database expects a string
$stmt->bind_param("s", $user_id);
if($stmt->execute())
{
/* bind result variables */
$stmt->bind_result($image);
/* fetch value */
$stmt->fetch();
echo $image;
}
else
{
echo "query failed";
}
$stmt->close();
$db_conn->close();
But every time I run the code I get this error:There was an error getting aws: Failed to connect to ec2-174-129-82-141.compute-1.amazonaws.com port 80: Timed out
Thanks for looking at the code and please let me know if there is anything else I can do to help.
You have to add a rule to open the port 80 using security groups (Inbound tab)
How your rule should look:
By default the port 80 is close in EC2 AWS instances.
And the URL is malformed in Unity
Add http:// to your server URL
In editor will work ok without http:// but it will fail in android.
Scenario:
I am trying to send a data (say String type) from C# сonsole application to Node.JS server through ZeroMQ.
Information:
Using clrzmq for c# and ZeroMQ libs for C# and Node.JS respectively
I am able to perform push-pull from Node.JS, also push - pull from C#.
So, one thing is confirmed that ZeroMQ - The Intelligent Transport Layer is installed on the machine (Windows 7 64-bit)
Issue:
I am not able to push data from C# Console app to Node.JS app (even tried vice-versa), both are on the same machine and on the same address i.e tcp://127.0.0.1:2222
Node.js code:
var zmq = require('zeromq.node');
var pull_socket = zmq.socket('pull');
pull_socket.connect('tcp://127.0.0.1:2222');
pull_socket.on('message', function (data) {
console.log('received data:\n');
console.log(data);
});
C# code:
namespace DataServiceEngine
{
class Program
{
static void Main(string[] args)
{
//clsApp App = new clsApp();
//App.appId = "001";
//App.name = "Back Office";
//Console.WriteLine("appId :" + App.appId + "\n");
//Console.WriteLine("name:" + App.name + "\n");
try
{
// ZMQ Context and client socket
using (var context = new Context(1))
{
using (Socket client = context.Socket(SocketType.PUSH))
{
client.Connect("tcp://127.0.0.1:2222");
string request = "Hello";
for (int requestNum = 0; requestNum < 10; requestNum++)
{
Console.WriteLine("Sending request {0}...", requestNum);
client.Send(request, Encoding.Unicode);
string reply = client.Recv(Encoding.Unicode);
Console.WriteLine("Received reply {0}: {1}", requestNum, reply);
}
}
}
}
catch (ZMQ.Exception exp)
{
Console.WriteLine(exp.Message);
}
}
}
}
Question: Can anyone tell me what may be the reason or where am I doing wrong?
I had the same issue (but I issued a communication Node.JS -> Node.JS). To solve the problem I used to do sendersocket.connect("tcp://"+host+":"+port); at the sender and receiversocket.bindSync("tcp://*:"+port); at the receiver.
Hope this fix your problem.