Unity Socket建立服务器客户端与mysql数据库互通,数据库返回数据转换成类
程序员文章站
2022-06-15 14:18:06
...
1.编写服务器和客户端用Socket互联
(1)编写MyServer服务器
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;
namespace SocketTest2
{
public class MyServer : MonoBehaviour
{
private static byte[] result = new byte[1024];
private const int port = 8080;
private static string IpStr = "127.0.0.1";
private static Socket serverSocket;
Thread thread;
List<Thread> ctList = new List<Thread>();
void Start()
{
IPAddress ip = IPAddress.Parse(IpStr);
IPEndPoint ip_end = new IPEndPoint(ip,port);
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(ip_end);
serverSocket.Listen(10);
Debug.Log("启动监听" + serverSocket.LocalEndPoint + "成功");
MyUseSQL.Instance();
thread = new Thread(ClientConnectListen);
thread.Start();
}
//监听客户端的链接
private void ClientConnectListen()
{
while (true)
{
Socket client = serverSocket.Accept();
Debug.Log(string.Format("客户端{0}成功链接", client.RemoteEndPoint));
ServerText serverText = new ServerText();
serverText.str = "链接服务器成功,把这条消息从服务器发送给客户端";
string json = JsonUtility.ToJson(serverText);
SendMessage(client, json);
//开启线程接收客户端信息
Thread clientThread = new Thread(ReciveMessage);
clientThread.Start(client);
ctList.Add(clientThread);
}
}
public void SendMessage(Socket client, string str)
{
ByteBuffer buffer = new ByteBuffer();
buffer.WriteString(str);
client.Send(buffer.ToBytes());
}
public MyData dataTest;
public void ReciveMessage(object obj)
{
Socket client = obj as Socket;
while (true)
{
try
{
int num = client.Receive(result);
ByteBuffer buff = new ByteBuffer(result);
string json = buff.ReadString();
ServerText serverText = JsonUtility.FromJson<ServerText>(json);
if (serverText.give.colTable != "" && serverText.give.colName != "")
{
serverText.str = "服务器返回数据库";
dataTest = MyUseSQL.Instance().SelectSql<MyData>(serverText.give.colTable, serverText.give.colName);
serverText.data = dataTest;
string newJson = JsonUtility.ToJson(serverText);
SendMessage(client,newJson);
}
if (serverText.isClose)
{
Debug.Log("关闭线程");
Thread.CurrentThread.Abort();
break;
}
Debug.Log("服务器收到"+client.RemoteEndPoint + "...."+serverText.str);
}
catch(Exception ex)
{
Debug.Log(ex.Message);
client.Shutdown(SocketShutdown.Both);
client.Close(0);
}
}
}
private void OnDestroy()
{
thread.Abort();
thread = null;
for (int i = 0; i < ctList.Count; i++)
{
ctList[i].Abort();
ctList[i] = null;
}
//serverSocket.Shutdown(SocketShutdown.Both);
//serverSocket.Close();
}
}
}
(2)MyClient客户端
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;
namespace SocketTest2
{
public class MyClient
{
private static Socket client;
public static byte[] result = new byte[1024];
public int port = 8080;
public string IpStr = "127.0.0.1";
private bool isConnect = false;
private Thread thread;
public ServerText serverText;
public MyClient()
{
client = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
}
public void OnConnectedToServer()
{
IPAddress ip = IPAddress.Parse(IpStr);
IPEndPoint ip_end = new IPEndPoint(ip, port);
try
{
isConnect = true;
client.Connect(ip_end);
Debug.Log("链接服务器成功");
thread = new Thread(ReciveMessage);
thread.Start();
}
catch
{
isConnect = false;
Debug.Log("链接服务器失败");
}
}
public void ReciveMessage()
{
while (true)
{
try
{
int num = client.Receive(result);
ByteBuffer buff = new ByteBuffer(result);
string json = buff.ReadString();
serverText = JsonUtility.FromJson<ServerText>(json);
Debug.Log(serverText.str);
}
catch (Exception ex)
{
Debug.Log(ex);
client.Shutdown(SocketShutdown.Both);
client.Close();
}
}
}
public void Send(object t)
{
if (isConnect)
{
string json = JsonUtility.ToJson(t);
ByteBuffer buff = new ByteBuffer();
buff.WriteString(json);
client.Send(buff.ToBytes());
}
}
public void Close()
{
ServerText t = new ServerText();
t.isClose = true;
Send(t);
thread.Abort();
//thread = null;
//client.Shutdown(SocketShutdown.Both);
//client.Close();
}
}
}
2.连接数据库
(1)SqlAccess控制类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MySql.Data.MySqlClient;
using System;
using System.Data;
namespace SocketTest2
{
public class SQLAccess
{
public MySqlConnection sqlConnecter;
public string host = "localhost";//172.16.16.191。
public void OpenSQL(string _host, string _SQLName, string _id, string _password, string _port)
{
try
{
string str = string.Format("Host={0};Database={1};User ID={2};Password={3};Port={4}", _host, _SQLName, _id, _password, _port);
sqlConnecter = new MySqlConnection(str);
sqlConnecter.Open();
Debug.Log("打开数据库成功");
}
catch (Exception ex)
{
Debug.Log("打开数据库失败" + ex.Message);
}
/// <summary>
/// 关闭数据库
/// </summary>
}
public void CloseSql()
{
if (sqlConnecter != null)
{
sqlConnecter.Close();
sqlConnecter.Dispose();
sqlConnecter = null;
}
}
/// <summary>
/// 执行语句
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public DataSet ExcuteStatements(string str)
{
if (sqlConnecter.State == ConnectionState.Open)
{
DataSet dataSet = new DataSet();
try
{
MySqlDataAdapter mySqlDataAdapter = new MySqlDataAdapter(str, sqlConnecter);
mySqlDataAdapter.Fill(dataSet);
Debug.Log("保存" + str + sqlConnecter);
}
catch (Exception e)
{
throw new Exception(e.Message.ToString());
}
finally { }
return dataSet;
}
return null;
}
/// <summary>
/// 创建表
/// </summary>
/// <param name="name">表名</param>
/// <param name="datas">数据</param>
/// <param name="types">数据类型</param>
/// <returns></returns>
public DataSet CreateTable(string name, string[] datas, string[] types)
{
if (datas.Length != types.Length)
{
throw new Exception("Wrong Input");
}
string query = "CREATE TABLE " + name + "(" + datas[0] + " " + types[0];
for (int i = 1; i < datas.Length; i++)
{
query += "," + datas[i] + " " + types[i];
}
query += ")";
return ExcuteStatements(query);
}
/// <summary>
/// 创建id自增的表
/// </summary>
/// <param name="name">表名</param>
/// <param name="datas">数据</param>
/// <param name="types">数据类型</param>
/// <returns></returns>
public DataSet CreateAutoIDTable(string name, string[] datas, string[] types)
{
if (datas.Length != types.Length)
{
throw new Exception("Wrong Input");
}
string query = "CREATE TABLE " + name + "(" + datas[0] + " " + types[0] + " NOT NULL AUTO_INCREMENT";
for (int i = 1; i < datas.Length; i++)
{
query += ", " + datas[i] + " " + types[i];
}
query += ", PRIMARY KEY (" + datas[0] + ")" + ")";
return ExcuteStatements(query);
}
/// <summary>
/// 插入一行指定列的值(不可用于自增id的表)
/// INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....)
/// </summary>
/// <param name="tableName">表名</param>
/// <param name="colNames">列名</param>
/// <param name="colValues">值</param>
/// <returns></returns>
public DataSet InsertPartRow(string tableName, string[] colNames, string[] colValues)
{
if (colNames.Length != colValues.Length)
{
throw new Exception("Wrong Input");
}
string query = "INSERT INTO " + tableName + " (" + colNames[0];
for (int i = 1; i < colNames.Length; i++)
{
query += ", " + colNames[i];
}
query += ") VALUES (" + "'" + colValues[0] + "'";
for (int i = 1; i < colValues.Length; i++)
{
query += ", " + "'" + colValues[i] + "'";
}
query += ")";
return ExcuteStatements(query);
}
/// <summary>
/// 插入一行所有列的值
/// INSERT INTO 表名称 VALUES (值1, 值2,....)
/// </summary>
/// <param name="tableName"></param>
/// <param name="colName"></param>
/// <returns></returns>
public DataSet InsertFullRow(string tableName, string[] colValues)
{
string query = "INSERT INTO " + tableName + " VALUES (" + "'" + colValues[0] + "'";
for (int i = 1; i < colValues.Length; i++)
{
query += ", " + "'" + colValues[i] + "'";
}
query += ")";
return ExcuteStatements(query);
}
/// <summary>
/// 删除某一行
/// DELETE FROM 表名称 WHERE 列名称 = 值
/// </summary>
/// <param name="tableName"></param>
/// <param name="colName"></param>
/// <param name="colValue"></param>
/// <returns></returns>
public DataSet DeleteOneRow(string tableName, string colName, string colValue)
{
string query = "DELETE FROM " + tableName + " WHERE " + colName + " = " + "'" + colValue + "'";
return ExcuteStatements(query);
}
/// <summary>
/// 删除多行 (满列则删除所有行)
/// DELETE FROM 表名称 WHERE 列名称 IN (值1, 值2, ...)
/// </summary>
/// <param name="tableName"></param>
/// <param name="colName"></param>
/// <param name="colValues"></param>
/// <returns></returns>
public DataSet DeleteMultipleRows(string tableName, string colName, string[] colValues)
{
string query = "DELETE FROM " + tableName + " WHERE " + colName + " IN (" + colValues[0];
for (int i = 1; i < colValues.Length; i++)
{
query += ", " + colValues[i];
}
query += ")";
return ExcuteStatements(query);
}
/// <summary>
/// 删除所有行
/// 1. DELETE FROM 表名称
/// 2. DELETE * FROM 表名称
/// </summary>
/// <param name="tableName"></param>
/// <returns></returns>
public DataSet DeleteAllRows(string tableName)
{
string query = "DELETE FROM " + tableName;
return ExcuteStatements(query);
}
/// <summary>
/// 更新某一行的一个列
/// UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值
/// </summary>
/// <param name="tableName">表名称</param>
/// <param name="updateColName">列名称</param>
/// <param name="updateColValue"></param>
/// <param name="selectColName"></param>
/// <param name="selectColValue"></param>
/// <returns></returns>
public DataSet UpdateOneCol(string tableName, string updateColName, string updateColValue, string selectColName, string selectColValue)
{
string query = "UPDATE " + tableName + " SET " + updateColName + " = " + "'" + updateColValue + "'" + " WHERE " +
selectColName + " = " + "'" + selectColValue + "'";
return ExcuteStatements(query);
}
/// <summary>
/// 更新某一行的若干列 (满列值则更新一整列)
/// </summary>
/// <param name="tableName">表名称</param>
/// <param name="updateColNames">列名称</param>
/// <param name="updateColValues">新值</param>
/// <param name="selectColName">新值</param>
/// <param name="selectColValue"> WHERE 列名称 = 某值</param>
/// <returns></returns>
public DataSet UpdateMultipleCols(string tableName, string[] updateColNames, string[] updateColValues, string selectColName, string selectColValue)
{
if (updateColNames.Length != updateColValues.Length)
{
throw new Exception("Wrong Input");
}
string query = "UPDATE " + tableName + " SET " + updateColNames[0] + " = " + "'" + updateColValues[0] + "'";
for (int i = 1; i < updateColNames.Length; i++)
{
query += ", " + updateColNames[i] + " = " + "'" + updateColValues[i] + "'";
}
query += " WHERE " + selectColName + " = " + "'" + selectColValue + "'";
return ExcuteStatements(query);
}
/// <summary>
/// 针对一行修改数据
/// </summary>
/// <param name="_tableName">表名</param>
/// <param name="_updateColName1">修改的列名</param>
/// <param name="_updateColValue1">修改的列值</param>
/// <param name="_updateColName2">修改的列名2</param>
/// <param name="_updateColValue2">修改的列值2</param>
/// <param name="setColName">要改的一行的列名</param>
/// <param name="setColValue">要改的一行列值</param>
/// <returns></returns>
public DataSet UpdateAimatCols(string _tableName, string _updateColName1, string _updateColValue1, string _updateColName2, string _updateColValue2, string setColName, string setColValue)
{
string query = string.Format("UPDATE {0} SET {1} = '{2}',{3}='{4}' WHERE {5}='{6}'", _tableName, _updateColName1, _updateColValue1, _updateColName2, _updateColValue2, setColName, setColValue);
Debug.Log(query);
return ExcuteStatements(query);
}
/// <summary>
/// 查询某一列
/// SELECT 列名称 FROM表名称
/// </summary>
/// <param name="tableName"></param>
/// <param name="colName"></param>
/// <returns></returns>
public DataSet SelectOneCol(string tableName, string colName)
{
string query = "SELECT " + colName + " FROM " + tableName;
return ExcuteStatements(query);
}
/// <summary>
/// 查询多列 (满列名则查询整表)
/// SELECT 列名称,列名称... FROM 表名称
/// </summary>
/// <param name="tableName">表名称</param>
/// <param name="colNames">列名称</param>
/// <returns></returns>
public DataSet SelectMultipleCols(string tableName, string[] colNames)
{
string query = "SELECT " + colNames[0];
for (int i = 1; i < colNames.Length; i++)
{
query += "," + colNames[i];
}
query += " FROM " + tableName;
return ExcuteStatements(query);
}
/// <summary>
/// 查询整表
/// SELECT * FROM 表名称
/// </summary>
/// <param name="tableName"></param>
/// <returns></returns>
public DataSet SelectAllCols(string tableName)
{
string query = "SELECT * FROM " + tableName;
return ExcuteStatements(query);
}
public DataSet SelectWhereCol(string tableName,string name, string id)
{
string query = "SELECT * FROM " + tableName + " WHERE " + name+ " = '" + id + "'";
Debug.Log(query);
return ExcuteStatements(query);
}
}
}
(2)MyUseSql链接数据库类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Data;
using System;
using System.Reflection;
namespace SocketTest2
{
public class MyUseSQL : MonoBehaviour
{
public string host = "172.16.16.191";
public string sqlname = "MyTest";
public string password = "12345678";
public string id = "root";
public string port = "3306";
public string tableName = "userclient";
public string colName = "11";
private static MyUseSQL instance;
public static MyUseSQL Instance()
{
if (instance == null)
{
instance = FindObjectOfType<MyUseSQL>();
if (instance == null)
{
string name = typeof(MyUseSQL).Name;
GameObject obj = GameObject.Find(name);
if (obj == null)
{
obj = new GameObject(name);
}
instance = obj.AddComponent<MyUseSQL>();
return instance;
}
}
return instance;
}
public SQLAccess sql;
public MyData dataTest;
public MyUseSQL()
{
try
{
sql = new SQLAccess();
sql.OpenSQL(host, sqlname, id, password, port);
//dataTest = SelectSql<MyData>("Id",colName);
}
catch (Exception ex)
{
Debug.Log(ex.Message);
}
}
public T SelectSql<T>(string _colTable,string _colName)
{
T enity = Activator.CreateInstance<T>();
try
{
DataSet data = sql.SelectWhereCol(tableName, _colTable, _colName);
if (data != null)
{
DataTable table = data.Tables[0];
//foreach (DataRow row in table.Rows)
//{
// foreach (DataColumn column in table.Columns)
// {
// Debug.Log(row[column]);
// }
//}
enity = TableToEntity<T>(table);
}
}
catch (Exception ex)
{
Debug.Log(ex.Message);
}
return enity;
}
public T TableToEntity<T>(DataTable dt, int rowindex = 0)
{
Type type = typeof(T);
T entity = Activator.CreateInstance<T>();
if (dt == null)
{
return entity;
}
DataRow row = dt.Rows[rowindex];
PropertyInfo[] pArray = type.GetProperties();
foreach (PropertyInfo p in pArray)
{
try
{
var obj = Convert.ChangeType(row[p.Name], p.PropertyType);
p.SetValue(entity, obj, null);
}
catch(Exception ex)
{
Debug.Log(ex.Message);
}
}
return entity;
}
}
}
3.创建数据类
(1)MyData(需要序列化)用于socket传输(转换json)
(2)用于数据库信息接收。
(3)流读写类ByteBuffer,用于socket传输信息读写。
using System.IO;
using UnityEngine;
using System;
using System.Text;
namespace SocketTest2
{
public enum DataType
{
SERVERTEXT = 0,
DATA = 1,
}
[Serializable]
public class MyData
{
public string id;
public string name;
public string pwd;
public int num;
public MyData(string _id, string _name, string _pwd, int _num)
{
id = _id;
name = _name;
pwd = _pwd;
num = _num;
}
public MyData() { }
public string Id { get => id; set => id = value; }
public string Name { get => name; set => name = value; }
public string Pwd { get => pwd; set => pwd = value; }
public int Num { get => num; set => num = value; }
}
[Serializable]
public class ServerText
{
public bool isClose = false;
public string str;
public GiveMe give;
public MyData data;
public ServerText()
{
give = new GiveMe();
data = new MyData();
}
}
[Serializable]
public class GiveMe
{
public string colTable = "";
public string colName = "";
}
public class ByteBuffer
{
MemoryStream stream = null;
BinaryWriter writer = null;
BinaryReader reader = null;
public ByteBuffer()
{
stream = new MemoryStream();
writer = new BinaryWriter(stream);
}
public ByteBuffer(byte[] data)
{
if (data == null)
{
stream = new MemoryStream();
writer = new BinaryWriter(stream);
}
else
{
stream = new MemoryStream(data);
reader = new BinaryReader(stream);
}
}
public void Close()
{
if (writer != null) writer.Close();
if (reader != null) reader.Close();
stream.Close();
stream = null;
writer = null;
reader = null;
}
public void WriteByte(byte v)
{
writer.Write(v);
}
public void WriteInt(int v)
{
writer.Write((int)v);
}
public void WriteShort(ushort v)
{
writer.Write((ushort)v);
}
public void WriteLong(long v)
{
writer.Write((long)v);
}
public void WriteFloat(float v)
{
byte[] temp = BitConverter.GetBytes(v);
Array.Reverse(temp);
writer.Write(BitConverter.ToSingle(temp, 0));
}
public void WriteDouble(double v)
{
byte[] temp = BitConverter.GetBytes(v);
Array.Reverse(temp);
writer.Write(BitConverter.ToDouble(temp, 0));
}
public void WriteString(string v)
{
byte[] bytes = Encoding.UTF8.GetBytes(v);
writer.Write((ushort)bytes.Length);
writer.Write(bytes);
}
public void WriteBytes(byte[] v)
{
writer.Write((int)v.Length);
writer.Write(v);
}
public byte ReadByte()
{
return reader.ReadByte();
}
public int ReadInt()
{
return (int)reader.ReadInt32();
}
public ushort ReadShort()
{
return (ushort)reader.ReadInt16();
}
public long ReadLong()
{
return (long)reader.ReadInt64();
}
public float ReadFloat()
{
byte[] temp = BitConverter.GetBytes(reader.ReadSingle());
Array.Reverse(temp);
return BitConverter.ToSingle(temp, 0);
}
public double ReadDouble()
{
byte[] temp = BitConverter.GetBytes(reader.ReadDouble());
Array.Reverse(temp);
return BitConverter.ToDouble(temp, 0);
}
public string ReadString()
{
ushort len = ReadShort();
byte[] buffer = new byte[len];
buffer = reader.ReadBytes(len);
return Encoding.UTF8.GetString(buffer);
}
public byte[] ReadBytes()
{
int len = ReadInt();
return reader.ReadBytes(len);
}
public byte[] ToBytes()
{
writer.Flush();
return stream.ToArray();
}
public void Flush()
{
writer.Flush();
}
}
}
4.接收数据库的DataTable转换为自定义类返回范型实例(在MyUseSQL中)
public T TableToEntity(DataTable dt, int rowindex = 0)
{
Type type = typeof(T);
T entity = Activator.CreateInstance();
if (dt == null)
{
return entity;
}
DataRow row = dt.Rows[rowindex];
PropertyInfo[] pArray = type.GetProperties();
foreach (PropertyInfo p in pArray)
{
try
{
var obj = Convert.ChangeType(row[p.Name], p.PropertyType);
p.SetValue(entity, obj, null);
}
catch(Exception ex)
{
Debug.Log(ex.Message);
}
}
return entity;
}
5.服务器使用链接数据库的类,进行对数据库操作
6.客户端向服务器发起申请,服务器返回对应数据库信息。
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;
namespace SocketTest2
{
public class MyClient
{
private static Socket client;
public static byte[] result = new byte[1024];
public int port = 8080;
public string IpStr = "127.0.0.1";
private bool isConnect = false;
private Thread thread;
public ServerText serverText;
public MyClient()
{
client = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
}
public void OnConnectedToServer()
{
IPAddress ip = IPAddress.Parse(IpStr);
IPEndPoint ip_end = new IPEndPoint(ip, port);
try
{
isConnect = true;
client.Connect(ip_end);
Debug.Log("链接服务器成功");
thread = new Thread(ReciveMessage);
thread.Start();
}
catch
{
isConnect = false;
Debug.Log("链接服务器失败");
}
}
public void ReciveMessage()
{
while (true)
{
try
{
int num = client.Receive(result);
ByteBuffer buff = new ByteBuffer(result);
string json = buff.ReadString();
serverText = JsonUtility.FromJson<ServerText>(json);
Debug.Log(serverText.str);
}
catch (Exception ex)
{
Debug.Log(ex);
client.Shutdown(SocketShutdown.Both);
client.Close();
}
}
}
public void Send(object t)
{
if (isConnect)
{
string json = JsonUtility.ToJson(t);
ByteBuffer buff = new ByteBuffer();
buff.WriteString(json);
client.Send(buff.ToBytes());
}
}![在这里插入图片描述](https://img-blog.csdnimg.cn/2019123111563932.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2JveVpoZW5HdWk=,size_16,color_FFFFFF,t_70)
public void Close()
{
ServerText t = new ServerText();
t.isClose = true;
Send(t);
thread.Abort();
//thread = null;
//client.Shutdown(SocketShutdown.Both);
//client.Close();
}
}
}
客户端连接服务器
客户端向服务器发送信息
客户端向服务器发送信息请求数据,服务器发送数据给客户端
本例子里头都是用数据类中的信息来进行判断,有好的办法欢迎评论,有错误的地方欢迎指出。
数据库截图
百度云链接:https://pan.baidu.com/s/1y2XXA4gbwaYBDJrO_VbzDw 密码:jllx
上一篇: 银行家算法的原理及代码实现
下一篇: Linux命令学习记录