Unity client and server communication [Unity network programming (4)]

1. Unity's UnityWebRequest class

UnityWebRequest provides a modular system for composing HTTP requests and processing HTTP responses. The main goal of the UnityWebRequest system is to allow Unity games to interact with the web browser backend.

1. HTTP transactions are decomposed into three distinct operations:

  • provide data to the server
  • Receive data from server
  • HTTP flow control (for example, redirection and error handling)

2. Can manage the following objects:

  • UploadHandler The object handles the transfer of data to the server
  • DownloadHandler Object handles reception, buffering and postprocessing of data received from the server
  • UnityWebRequest The object manages the other two objects and also handles HTTP flow control. This object is where custom headers and URLs are defined, and where error and redirect information is stored.

3. The flow of an HTTP transaction is as follows:

  • Create a web request object
  • Configure the web request object
    • Set custom headers
    • Set HTTP verbs (such as GET, POST, and HEAD - all platforms except Android allow custom verbs)
    • Set URL * (Optional) Create an upload handler and attach it to the web request
    • Provide data to upload
    • Provide an HTTP form to upload* (Optional) Create a download handler and attach it to the web request
  • send web request
    • If in a coroutine, get  Send() the result of the call to wait for the request to complete  (optional) read the data received from the download handler  (optional) read the error message, HTTP status code and response headers from the UnityWebRequest object

4. The format of a request message is as follows:

 5. Return status code

Through www.responseCode, you can get the return status code:

 200 means normal

Most of the 404 is that the url is wrong

500 is mostly a server program error

2. Code implementation of the Unity client:

1. Implementation of login function (GET request)

    public string url_base = "http://127.0.0.1:5566";
    public void Login(string username, string pwd)
    {
        StartCoroutine(login(username, pwd));
    }

    // 登录:"http://127.0.0.1:5566/login/?username=qwer&pwd=qwert"   
    IEnumerator login(string username, string password)
    {
        string url = url_base + "/login/?username=" + username + "&pwd=" + password;
        UnityWebRequest www = UnityWebRequest.Get(url);
        yield return www.SendWebRequest(); // 等待成功发送请求
        if (www.isNetworkError || www.isHttpError)
        {
            Debug.Log(www.error);
        }
        else
        {
            Debug.Log(www.downloadHandler.text); // 返回结果
        }
    }

2. Realization of sending data function (POST request)

The type of each table in the database is defined here, as long as an object is created, it can be sent to the server

[Serializable]
    public class Insert<T>
    {
        public string tablename;
        public T datarow;// 需要插入的数据,只有一行
    }
    // 数据库中的一个表的类型
    [Serializable]
    public class users
    {
        public int id = 0;
        public string name = "";
        public int age = 0;
        public users() { }
        public users(int i, string n, int a)
        {
            id = i;
            name = n;
            age = a;
        }
    }

It is also necessary to perform string-to-byte conversion. Here are the differences between different character types:

ASCII 0-255 1 byte, excluding Chinese
Unicode (Universal Code) Defines the encoding value of characters (including Chinese), but does not define the storage method (hexadecimal) [for example, one letter is 1 byte, but Chinese It may also require 4 bytes]
UTF-8 defines the Unicode storage method, which is a variable-length solution that can use 1 to 6 bytes for storage.
UTF-16: A solution between UTF-8 and UTF-32, using 2 bytes or 4 bytes for storage
UTF-32: A fixed 4-byte storage method, one-to-one encoding is enough, simple But the storage efficiency is too low
json: it is actually a string, but in the form of key-value pairs


    //字符串格式转换为字节
    public static byte[] StringToBytes(string StringMessage)
    {
        //字符串转UTF-8 byte
        //string StringMessage = "Hello World How Are you? Pi /u03C0 Yen /uFFE5";
        System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();
        return UTF8.GetBytes(StringMessage);
    }
    

3. Realize establishment request and data sending:

public string url_base = "http://127.0.0.1:5566";
    public void InsertData<T>(Insert<T> se)
    {
        StartCoroutine(Send_data<T>(se));
    }
    // 数据发送(表名、数据一行)
    IEnumerator Send_data<T>(Insert<T> Send)
    {
        string url = url_base + "/insert/";

        // 发送内容
        /*
         * {
         *  "tablename":"users",
         *  "datarow":{"id":60,"name":"test","age":123}   //每个类不一样
         *  }
         */

        string json_str = JsonUtility.ToJson(Send); // 转换成json格式
        byte[] byte_data = StringToBytes(json_str);// 转换成字节流形式

        print("发送" + json_str);

        // 通过上传handler发送字节数据
        UnityWebRequest www = new UnityWebRequest(url, "POST");
        www.uploadHandler = (UploadHandler)new UploadHandlerRaw(byte_data);     // 上传数据
        www.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); // 接收数据
        www.SetRequestHeader("Content-Type", "application/json"); //请求头 "application/x-www-form-urlencoded"
        print("数据请求状态码:" + www.responseCode);
        yield return www.SendWebRequest();

        if (www.isHttpError || www.isNetworkError)
        {
            Debug.LogError(www.error);
        }
        else
        {
            Debug.Log("data upload compelete:");
            Debug.Log(www.downloadHandler.text);
        }
    }

3. Implementation of the server code:

from flask import Flask,request,jsonify,make_response,json,redirect
from flask import request
app = Flask(__name__) 

@app.route('/login/', methods=["GET"])
def login():
    username = request.args.get('username')
    pwd = request.args.get('pwd')
    print("type:"+usertype)
    # 接收处理
    if username=='test' and pwd=='XXX'
        return "Success"
    return "Fail"

@app.route('/insert/',methods=['POST'])
def insert_data():
    print("插入,接收数据:",request.data)
    str_req = request.get_data(as_text=True)
    dic_data = json.loads(str_req) #转换为字典类型
    print(dic_data)
    # TODO:解析不同的数据,并且通过数据库返回不同数据
    return "Result"

if __name__=='__main__':
    print(app.url_map) # 打印url的路由映射
    app.run(host='127.0.0.1',port=5566,debug=False)

4. The server processes the database

Take the login request as an example:

The function can be encapsulated, the data received by the server can be passed here for processing, and the result can be returned

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column,Integer,String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import scoped_session
from sqlalchemy.dialects.mysql import INTEGER, DATETIME, REAL, TEXT, VARCHAR,BLOB
from sqlalchemy import Table, Column, ForeignKey, MetaData
from sqlalchemy.orm import mapper, sessionmaker
from sqlalchemy import  func

class UserLogin():
    def __init__(self) -> None:
        #连接数据库
        #初始化数据库连接# '数据库类型+数据库驱动名称://用户名:口令@机器地址:端口号/数据库名'
        self.url = sql_url
        engine = create_engine(self.url,encoding="utf-8",echo=False)
        #创建session类型
        DBSession = sessionmaker(bind=engine)
        #创建session对象
        self.session = DBSession()
    def login(self,username,pwd):
        sql_str = "SELECT * FROM account WHERE username='"+str(username) +"' and pwd='"+str(pwd)
        print(sql_str)
        try:
            cursor = self.session.execute(sql_str) 
            result = cursor.fetchall()
            if(len(result) == 0):
                return "登录失败"
        except Exception as e:
            print(e)
            return "登录失败!"
        return "登录成功"

Guess you like

Origin blog.csdn.net/cycler_725/article/details/127902189