本来是跟着课程学习,但是后来发现课程用搭建好的服务器进行网络访问,而且采用的是内存存储,一旦关闭,数据全部丢失,无法做到持久化存储,因此特地编写服务器。

网络传输采用异步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 initialization
	void 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 frame
	void 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。

希望对大家有帮助,靴靴