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。

希望对大家有帮助,靴靴