Unity网络开发实践
来源:互联网 发布:有哪些域名交易网站 编辑:程序博客网 时间:2024/06/05 16:33
本来是跟着课程学习,但是后来发现课程用搭建好的服务器进行网络访问,而且采用的是内存存储,一旦关闭,数据全部丢失,无法做到持久化存储,因此特地编写服务器。
网络传输采用异步Tcp连接,传输格式为Json,本人用的是LitJson,当然用newtonsoft也是可以的。
先说一下第一次遇到的问题,Invalid character ’,由于UTF8格式编码带有bom头,我就猜测是由于bom头影响了数据传输的准确性,使得服务器端得到的数据变长了3bytes,因此我调用了一下代码
//用于去掉bom头 public static string GetUTF8String(byte[] buffer,int n) { byte[] bomBuffer = new byte[] { 0xef, 0xbb, 0xbf }; if (buffer == null || buffer.Length <= 3 || (buffer[0] == bomBuffer[0] && buffer[1] == bomBuffer[1] && buffer[2] == bomBuffer[2])) { print("在这里边"); } else { print("不在"); } if (buffer == null) { return null; Debug.Log("传输得到的字符串为空"); } if (buffer.Length <= 3) { print("传输得到的字符串<3"); return Encoding.UTF8.GetString(buffer); } if (buffer[0] == bomBuffer[0] && buffer[1] == bomBuffer[1] && buffer[2] == bomBuffer[2]) { print("传输得到的字符串正在去bom头"); return new UTF8Encoding(false).GetString(buffer, 3, buffer.Length - 3); } print("我多接收到的长度为"+buffer.Length); return Encoding.UTF8.GetString(buffer,0,n); }随后发现问题仍无法解决,后来经过好长时间的测试后,发现导致这一问题出现,并不是只有bom头,还有可能是越界问题。越界问题的意思就是开的数组够大,当你进行Encoiing.UTF8.getString()时,它会对整个长度的数组进行转化,导致这个问题出现,因此需要用三个参数的getstring,规定长度0到length
第二个遇到的问题就是数据存储,本人采用的是mysql,目前刚刚完成用户登录以及注册,
mysql的访问
public static MySqlConnection dbConnection; private static string host = "localhost"; private static string id = "root"; private static string pwd = ""; private static string database = ""; private static string Connection_String = "";// Use this for initializationvoid Start () { Connection_String = string.Format("Server ={0};Database = {1};User ID ={2}; Password ={3};",host,database,id,pwd); openSqlConnection(Connection_String); string p = QueryTable("ly"); Debug.Log(p); }// Update is called once per framevoid Update () {} public static void openSqlConnection(string connectionstring) { dbConnection = new MySqlConnection(Connection_String); dbConnection.Open(); } public static void closeSqlConnection() { dbConnection.Close(); dbConnection = null; } public static void InsertUser(string user_name,string pass_word) { print("至少进来了"); MySqlCommand mySqlCommand = new MySqlCommand("insert into user values( '" + user_name + "','" + pass_word + "');", dbConnection); try { int reasult = mySqlCommand.ExecuteNonQuery();//用于测试是否真正的插入 if (reasult > 0) { Debug.Log("插入成功"); } else { Debug.Log("插入失败"); } } catch { } finally { } } public static string QueryTable(string userName) { MySqlCommand mySqlCommand = new MySqlCommand("Select * from user where user_name = '" + userName + "';", dbConnection); MySqlDataReader reader = mySqlCommand.ExecuteReader(); try { while (reader.Read()) { if (reader.HasRows) { if (reader.GetString(0).Equals(userName)) return reader.GetString(1); } } return null; } catch (Exception e) { Debug.Log(e.StackTrace); Debug.Log("查询失败"); return null; } finally { reader.Close(); } }
后来发现一个问题,当传入的string不正确时,也就是sql语句不合法时,不会报错,同时以后的代码也不会执行。
第三个问题就是异步连接的问题,目前我所搭建的连接还有些许问题,采用的是异步方式,用ReceiveCallBack处理服务器返回的信息,下面是客户端代码,已经全部加了注释,应该很容易看懂。
public class SocketConnect { private static SocketConnect connect; private static Socket socket_Tcp; private static string ip = "127.0.0.1"; private static int port = 10100; private static byte[] buff=new byte[1024]; private static List<SocketModel> messageList = new List<SocketModel>(); //用于获得SoketConnect public static SocketConnect GetInit() { if (connect == null) { connect = new SocketConnect(); Init_Socket(); } return connect; //如果该SocketConnect为空则new一个(并进行新的连接尝试),否则直接返回 } public static void Init_Socket() { try { socket_Tcp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //该Socket用于网络连接,采用流方式,使用TCP连接 socket_Tcp.Connect(ip,port); Debug.Log("连接成功"); socket_Tcp.BeginReceive(buff, 0, 1024, SocketFlags.None,ReceiveCallBack, socket_Tcp); //用于监听网络消息,BeiginReceive用于接收消息,ReceiveCallBack为回调方法当buff接受完全时进行回调 //参数一用于存储接收到的数据 //参数23 ,从零开始接受1024bytes,4不用管,值按位组合 //参数5,操作完成时回调该方法 //参数6用于将该数组传给BeiginRecive调用后返回的IAsyncResult方法 } catch { Debug.Log("连接失败"); } } //BeiginReceived的回调方法 //其中ar用于存储异步操作的状态信息以及所有定义的用户数据。 private static void ReceiveCallBack(IAsyncResult ar) { Socket socket = ar.AsyncState as Socket; try {//获取消息体长度 int length = socket.EndReceive(ar); string s = Encoding.UTF8.GetString(buff,0,length); Debug.Log("收到消息"); Debug.Log(s); readMessage(s); //将读取到的数据从buff的0开始读取readCount长度到temp的从0开始的位置、此处即为复制 } catch(Exception e) { Debug.Log(e.Message); Debug.Log(e.StackTrace); SocketModel model = new SocketModel(); model.type = Protocol.abort; string abort = codng<SocketModel>.encode(model); byte[] buffer = Encoding.UTF8.GetBytes(abort); socket_Tcp.Send(buffer); socket_Tcp.Close(); Debug.Log("网络错误,连接失败"); } socket_Tcp.BeginReceive(buff, 0, 1024, SocketFlags.None,ReceiveCallBack, socket); //实现反复读取,反复解析 } //用于返回SocketModel的List列表 public List<SocketModel> getlist() { return messageList; } // private static void readMessage(string s ) { try { Debug.Log(s); SocketModel model = codng<SocketModel>.decode(s); messageList.Add(model); } catch (Exception e) { Debug.Log(e.Message); Debug.Log(e.StackTrace); } } public void sendMessage(int type, int area, int command, string message) { SocketModel model = new SocketModel(); model.type = type; model.area = area; model.command = command; model.message = message; String trans = codng<SocketModel>.encode(model); byte[] buffer = Encoding.UTF8.GetBytes(trans);//测试用,下次删掉 string o =Encoding.UTF8.GetString(buffer); Debug.Log("is " + o ); // Debug.Log(buffer.Length+ "~~~~~~~~~~~ ");//测试用,下次删掉 Debug.Log(trans); SocketModel model1 = codng<SocketModel>.decode(trans); Debug.Log("type:" + model1.type + " area" + model1.area + " command: " + model1.command + " message:" + model1.message); byte[] bytes = new byte[trans.Length * sizeof(char)]; Buffer.BlockCopy(trans.ToCharArray(), 0, bytes, 0, bytes.Length); string s = ""; for (int i = 0; i < bytes.Length; i++) { s += bytes[i]; } Debug.Log(bytes.Length); Debug.Log(s+" ~~~~~~~~~~~~"); string y = "{\"type\":0,\"area\":0,\"command\":2,\"message\":\"{\\\"userName\\\":\\\"sdsd\\\",\\\"passWord\\\":\\\"dsd\\\"}\"}"; Debug.Log(y); SocketModel model2 = codng<SocketModel>.decode(y); Debug.Log("type:" + model2.type + " area" + model2.area + " command: " + model2.command + " message:" + model2.message); try { socket_Tcp.Send(buffer); // socket_Tcp.Send(bytes);//测试用,下次删掉 Debug.Log("Send"); } catch { Debug.Log("发送失败"); } }}
最后一个问题就是,服务器是多开的,就是可以有多个客户端连接,那么怎么实现每个线程发送的信息对应特定的client呢,因此就需要包装一个结构,当开启这个线程时,获得此网络传输模块,并为他封装上一个ip地址,并用一个dictionary存储所有的ip与socket,从而可以读取特定的socket。
希望对大家有帮助,靴靴
阅读全文
1 0
- Unity网络开发实践
- unity开发: socket网络连接
- unity开发:Qt C++与unity之间TCP网络通信
- unity开发:Qt C++与unity之间UDP网络通信
- 【unity系统模块开发】unity网络层读写
- unity开发:TCP socket网络连接
- unity开发:UDP socket网络连接
- unity 移动开发- 网络数据缓存
- Unity游戏开发网络基础(1)
- Unity游戏开发网络基础(2)
- Unity游戏开发网络基础(3)
- 《WebGIS开发实践手册》1.2 网络GIS
- iOS开发实践之网络检测Reachability
- Java 开发实践 网络编程 详解
- C++后台开发 网络编程实践一
- Unity网络多玩家游戏开发教程第1章Unity自带网络功能
- Unity网络多玩家游戏开发教程第1章Unity自带网络功能
- Unity网络多玩家游戏开发教程(上册)
- 阿里云前端周刊
- Java 多线程操作
- 微信浏览器中的video
- C++速查
- Java和JavaScript中使用Json方法大全
- Unity网络开发实践
- JS-Math对象
- Eclipse下struts框架的简单搭建
- android string.xml中包含百分号时报错 问题记录
- 实战
- 有史以来最详细的正则表达式入门教程
- Java中的数据类型
- 最简洁的PHP程序员学习路线及建议
- Struts2与Spring3 MVC性能比较 (MVC性能测试)