天蝎网站建设seo查询官网
5.客户端实现注册与登录接口
创建好UI



接下来定义发给客户端的协议等
public class MessageHelper
{//发送登录的消息给服务器 1002public void SendLoginMsg(string account, string pwd){LoginMsgC2S msg = new LoginMsgC2S();msg.account = account;msg.password = pwd;var str = JsonHelper.ToJson(msg);//json格式化注册请求SendToServer(1002, str);//发送}public Action<LoginMsgS2C> loginHandle;//处理登录(结果)请求private void LoginMsgHandle(byte[] obj){var str = Encoding.UTF8.GetString(obj);//将接受的消息从字节转换为stringLoginMsgS2C msg = JsonHelper.ToObject<LoginMsgS2C>(str);//在从json格式的string转为对应LoginMsgS2CloginHandle?.Invoke(msg);//如果处理注册消息的事件有订阅,就执行。}//发送聊天信息给服务器public void SendChatMsg(string account, string chat){ChatMsgC2S msg = new ChatMsgC2S();msg.player = account;msg.msg = chat;msg.type = 0;var str = JsonHelper.ToJson(msg);//json格式化注册请求SendToServer(1003, str);//发送}public Action<ChatMsgS2C> chatHandle;//处理聊天(转发)请求private void ChatMsgHandle(byte[] obj){var str = Encoding.UTF8.GetString(obj);//将接受的消息从字节转换为stringChatMsgS2C msg = JsonHelper.ToObject<ChatMsgS2C>(str);//在从json格式的string转为对应ChatMsgS2CchatHandle?.Invoke(msg);//如果处理注册消息的事件有订阅,就执行。}//发送注册的消息给服务器 1001public void SendRegisterMsg(string account, string email, string pwd){RegisterMsgC2S msg = new RegisterMsgC2S();msg.account = account;msg.email = email;msg.password = pwd;var str = JsonHelper.ToJson(msg);//json格式化注册请求SendToServer(1001, str);//发送}public Action<RegisterMsgS2C> registerHandle;//处理注册(结果)请求private void RigisterMsgHandle(byte[] obj){var str = Encoding.UTF8.GetString(obj);//将接受的消息从字节转换为stringRegisterMsgS2C msg = JsonHelper.ToObject<RegisterMsgS2C>(str);//在从json格式的string转为对应RegisterMsgS2CregisterHandle?.Invoke(msg);//如果处理注册消息的事件有订阅,就执行。}
}//1002
public class LoginMsgC2S
{public string account;public string password;
}public class LoginMsgS2C
{public string account;public string password;public int result;//0成功 1失败:账号或密码错误
}//1001
public class RegisterMsgC2S
{public string account;public string email;public string password;
}public class RegisterMsgS2C
{public string account;public string email;public string password;public int result;//0成功 1失败:已被注册的账号
}//1003
public class ChatMsgC2S
{public string player;public string msg;public int type;//0世界聊天
}//服务器转发给所有在线的客户端
public class ChatMsgS2C
{public string player;public string msg;public int type;//0世界聊天
}
创建Unity-Scripts/View/LoginView.cs和ChatView.cs
逻辑:LoginView用于UI界面按钮控制,调用MessageHelper里面的方法,发送和处理消息
public class LoginView : MonoBehaviour
{private GameObject register;//注册相关private Button registerBtn;private InputField usernameInput_Register;private InputField emailInput_Register;private InputField passwordInput_Register;private Button registerBtn_Register;private Button closeBtn_Register;//登录相关private Button loginBtn;private InputField usernameInput_Login;private InputField passwordInput_Login;// Start is called before the first frame updatevoid Start(){register = transform.Find("Register").gameObject;//打开注册界面registerBtn = transform.Find("RegisterBtn").GetComponent<Button>();registerBtn.onClick.AddListener(OpenRegisterView);//关闭注册界面closeBtn_Register = transform.Find("Register/CloseBtn").GetComponent<Button>();closeBtn_Register.onClick.AddListener(CloseRegisterView);//注册界面输入框usernameInput_Register = transform.Find("Register/UsernameInput/InputField").GetComponent<InputField>();emailInput_Register = transform.Find("Register/EmailInput/InputField").GetComponent<InputField>();passwordInput_Register = transform.Find("Register/PasswordInput/InputField").GetComponent<InputField>();//注册界面-注册按钮registerBtn_Register = transform.Find("Register/RegisterBtn").GetComponent<Button>();registerBtn_Register.onClick.AddListener(RegisterOnClick);//登录界面-登录按钮loginBtn = transform.Find("LoginBtn").GetComponent<Button>();loginBtn.onClick.AddListener(LoginOnClick);usernameInput_Login = transform.Find("UsernameInput/InputField").GetComponent<InputField>();passwordInput_Login = transform.Find("PasswordInput/InputField").GetComponent<InputField>();//处理登录结果MessageHelper.Instance.loginHandle += LoginHandle;MessageHelper.Instance.registerHandle += RegisterHandle;}// Update is called once per framevoid Update(){}private void CloseRegisterView(){register.gameObject.SetActive(false);}private void OpenRegisterView(){register.gameObject.SetActive(true);}private void LoginHandle(LoginMsgS2C obj){if (obj.result == 0){//登录成功将用户信息和返回的用户信息绑定起来,使用PlayerData类PlayerData.Instance.LoginMsgS2C = obj;Debug.Log("登陆成功");//this.gameObject.SetActive(false);Destroy(this.gameObject);var chatView = Resources.Load<GameObject>("ChatView");var chatObj = GameObject.Instantiate<GameObject>(chatView);chatObj.AddComponent<ChatView>();}else{Tips($"登录失败,错误码:{obj.result}");}}private void RegisterHandle(RegisterMsgS2C obj){if (obj.result == 0){Debug.Log("注册成功");Tips("注册成功");register.gameObject.SetActive(false);usernameInput_Login.text = obj.account;passwordInput_Login.text = obj.password;}else{Tips($"注册失败,错误码:{obj.result}");}}private void LoginOnClick(){if (string.IsNullOrEmpty(usernameInput_Login.text)){Tips("请输入账号!!!");return;}if (string.IsNullOrEmpty(passwordInput_Login.text)){Tips("请输入邮箱!!!");return;}//发送数据给服务器MessageHelper.Instance.SendLoginMsg(usernameInput_Login.text, passwordInput_Login.text);}private void RegisterOnClick(){if (string.IsNullOrEmpty(usernameInput_Register.text)){Tips("请输入账号!!!");return;}if (string.IsNullOrEmpty(emailInput_Register.text)){Tips("请输入邮箱!!!");return;}if (string.IsNullOrEmpty(passwordInput_Register.text)){Tips("请输入密码!!!");return;}//发送数据给服务器MessageHelper.Instance.SendRegisterMsg(usernameInput_Register.text, emailInput_Register.text, passwordInput_Register.text);}private GameObject _tipsObj;public void Tips(string str){if (_tipsObj != null){GameObject.Destroy(_tipsObj);}var tipsItem = transform.Find("TipsItem").gameObject;_tipsObj = GameObject.Instantiate<GameObject>(tipsItem);_tipsObj.transform.SetParent(this.transform, false);var content = _tipsObj.transform.Find("Text").GetComponent<Text>();content.text = str;_tipsObj.gameObject.SetActive(true);GameObject.Destroy(_tipsObj, 1.5f);}private void OnDestroy(){MessageHelper.Instance.loginHandle -= LoginHandle;MessageHelper.Instance.registerHandle -= RegisterHandle;}
}
创建Unity-Scripts/PlayerData.cs
public class PlayerData
{private static PlayerData instance = new PlayerData();public static PlayerData Instance => instance;public LoginMsgS2C LoginMsgS2C;
}
测试运行。

6.服务端处理注册与登录业务
将Unity MessageHelper里的消息类C2S、S2C等复制到Server-MessageHelper中
class MessageHelper
{
}//1002
public class LoginMsgC2S
{public string account;public string password;
}public class LoginMsgS2C
{public string account;public string password;public int result;//0成功 1失败:账号或密码错误
}//1001
public class RegisterMsgC2S
{public string account;public string email;public string password;
}public class RegisterMsgS2C
{public string account;public string email;public string password;public int result;//0成功 1失败:已被注册的账号
}//1003
public class ChatMsgC2S
{public string player;public string msg;public int type;//0世界聊天
}//服务器转发给所有在线的客户端
public class ChatMsgS2C
{public string player;public string msg;public int type;//0世界聊天
}
Server-Client理论上需要进入数据库判断有无账号,然后处理业务,这里用一个类Server/PlayerData.cs缓存这些数据,不用数据库了
namespace Server
{internal class PlayerData{private static PlayerData instance = new PlayerData();public static PlayerData Instance => instance;//单例Dictionary<string, RegisterMsgS2C> userMsg = new Dictionary<string, RegisterMsgS2C>();//缓存注册信息//注册后,result=0表示注册成功,将这个注册后的信息返回给客户端public RegisterMsgS2C Add(RegisterMsgC2S msgC2S){var item = new RegisterMsgS2C();userMsg[msgC2S.account] = item;item.account = msgC2S.account;item.password = msgC2S.password;item.result = 0;return item;}//判断是否存在相同的账号public bool Contain(string account){return userMsg.ContainsKey(account);}//维护已经登陆的用户Dictionary<string, Client> LoginUser = new Dictionary<string, Client>();public void AddLoginUser(string account, Client client){LoginUser[account] = client;}public Dictionary<string, Client> GetAllLoginUser(){return LoginUser;}}
}
//处理注册请求
private void RegisterMsgHandle(byte[] obj)
{var msg = JsonHelper.ToObject<RegisterMsgC2S>(obj);RegisterMsgS2C response = null;if (PlayerData.Instance.Contain(msg.account)){response = new RegisterMsgS2C();response.result = 1;//已经包含该帐号了}else{response = PlayerData.Instance.Add(msg);}SendToClient(1001, JsonHelper.ToJson(response));
}//处理登录请求
private void LoginMsgHandle(byte[] obj)
{//判断账号和密码是否跟缓存的一直,如果是,返回账号和密码var msg = JsonHelper.ToObject<LoginMsgC2S>(obj);LoginMsgS2C response = new LoginMsgS2C();if (PlayerData.Instance.Contain(msg.account)){response.result = 0;//已包含该账号response.account = msg.account;response.password = msg.password;//将用户储存起来PlayerData.Instance.AddLoginUser(msg.account, this);}else{response.result = 1;//账号或密码错误}SendToClient(1002, JsonHelper.ToJson(response));
}
运行测试,表明服务器收到了Unity客户端的注册信息后,在PlayerData中检测没有账号后,注册了一条数据,并返回给Unity客户端注册成功

再次注册同样的数据,表示注册失败,返回result = 1

用刚刚的账号登录,就登录成功了

为什么Unity和Server的输出都是乱码呢,因为直接输出的是包体大小+协议id+包体,所以前面是乱码,只输出包体就不会乱码,一下为修改了在send和receive时只输出body内容,输出内容正常。
