一、搭建Unity聊天室UI界面
简单UI拖拽一下:
聊天室实现步骤:
1.向服务器发送消息
2.刷新Content聊天界面
3.清空输入框
将InputField中输入的消息发给服务器
代码:
chatPanel:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class ChatPanel : MonoBehaviour
{
StringBuilder stringBuilder=new StringBuilder("");
TMP_InputField TMP_input;
Button button;
InputField inputfield;
Text content;
//获取相关的组件
private void Awake()
{
TMP_input = transform.Find("InputField").GetComponent<TMP_InputField>();
content = GameObject.Find("Content").GetComponent<Text>();
button = transform.Find("Btn_Send").GetComponent<Button>();
button.onClick.AddListener(OnSend);
}
// Start is called before the first frame update
void Start()
{
}
private void OnSend()
{
if (string.IsNullOrEmpty(TMP_input.text))
{
return;
}
Debug.Log(TMP_input.text);
//将内容发送给服务器
NetManager.Instance.SendMessageToServer(TMP_input.text);
//刷新界面
UpdateContent(TMP_input.text);
//将输入框清空
TMP_input.text = "";
}
void UpdateContent(string message)
{
stringBuilder.AppendLine(message);
content.text = stringBuilder.ToString();
}
// Update is called once per frame
void Update()
{
}
}
问题:为什么要使用到StringBuilder,有什么好处?StringBuilder常见的API有哪些?
NetManager:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
public class NetManager : MonoBehaviour
{
//单例
private static NetManager _instance = null;
public static NetManager Instance
{
get
{
return _instance;
}
}
// Start is called before the first frame update
//客户端连接服务器
//1.连接到服务器
//2.接受服务器的消息,并处理
//3.向服务器发送消息
byte[] msgArr = new byte[1024];
Socket clientSocket = null;
//消息队列,用于处理消息
Queue<string> messageQueue = new Queue<string>();
private void Awake()
{
_instance = this;
}
void Start()
{
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSocket.Connect(new IPEndPoint(IPAddress.Parse(Protocol.ProtocolConfig.ip), Protocol.ProtocolConfig.port));
Debug.Log("客户端开始连接服务器!");
try
{
clientSocket.BeginReceive(msgArr, 0, msgArr.Length, SocketFlags.None, AsyncReceive, clientSocket);
}
catch (System.Exception e)
{
Debug.Log(e.Message);
}
}
//接受服务器的消息
private void AsyncReceive(IAsyncResult ar)
{
Socket clientSocket = ar.AsyncState as Socket;
if (clientSocket == null)
{
return;
}
int length = clientSocket.EndReceive(ar);
string message = Encoding.UTF8.GetString(msgArr, 0, length);//接受的消息,思考为啥不在这个函数里面处理消息
//异步的本质是一条多线程,很多Unity的API没有办法在支线程中使用
messageQueue.Enqueue(message);
clientSocket.BeginReceive(msgArr, 0, msgArr.Length, SocketFlags.None, AsyncReceive, clientSocket);
}
public void SendMessageToServer(string message)
{
clientSocket.Send(Encoding.UTF8.GetBytes(message));
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.W))
{
SendMessageToServer("helloWorld");
}
if (messageQueue.Count>0)
{
string message = messageQueue.Dequeue();
//处理这个消息
Debug.Log(message);
}
}
}
加上服务器运行截图:
二、消息号改写聊天室
代码:
服务端:
动态链接库:ProtocolConfig:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Protocol
{
//class,struct,interface默认的访问权限修饰符为internal
public class ProtocolConfig
{
public const string ip = "192.168.1.";
public const int port = 8899;
}
}
动态链接库:ProtocolEnum:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Protocol
{
public enum ProtocolEnum
{
loginReq=1,
loginRep,
registerReq,
registerRep,
updateChat,
}
}
动态链接库:SocketMessage:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Protocol
{
public class SocketMessage
{
public ProtocolEnum messageId;
public string message;
public SocketMessage(ProtocolEnum messageId, string message)
{
this.messageId = messageId;
this.message = message;
}
public byte[] PackMessage()
{
byte[] idArr = BitConverter.GetBytes((int)messageId);
byte[] msgArr = Encoding.UTF8.GetBytes(message);
byte[] result = idArr.Concat(msgArr).ToArray();
return result;
}
public static SocketMessage Parse(byte[] msgArr)
{
ProtocolEnum _messageId = (ProtocolEnum)BitConverter.ToInt32(msgArr, 0);
string _message = Encoding.UTF8.GetString(msgArr, 4, msgArr.Length - 4);
return new SocketMessage(_messageId,_message);
}
}
}
Main函数:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Protocol;
namespace AsyncChatServer
{
class Program
{
static void Main(string[] args)
{
try
{
Socket Serversocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Serversocket.Bind(new IPEndPoint(IPAddress.Parse(ProtocolConfig.ip),ProtocolConfig.port));
Serversocket.Listen(10);
Console.WriteLine("服务器启动了");
Serversocket.BeginAccept(AsyncAccept, Serversocket);
}
catch (Exception e)
{
Console.WriteLine("1"+e.Message);
}
Console.ReadKey();
}
static byte[] msgarr = new byte[1024];
private static void AsyncAccept(IAsyncResult ar)
{
Socket serversocket = ar.AsyncState as Socket;
if (serversocket == null)
{
return;
}
Socket clientsocket = serversocket.EndAccept(ar);
ClientPeer clientPeer = new ClientPeer(clientsocket);
NetManager.Instance.AddClient(clientPeer);
Console.WriteLine(NetManager.Instance);
Console.WriteLine(clientsocket.RemoteEndPoint.ToString());
//clientsocket.beginreceive(msgarr, 0, msgarr.length, socketflags.none, asyncreveive, clientsocket);
serversocket.BeginAccept(AsyncAccept, serversocket);
}
}
}
NetManager:
using Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace AsyncChatServer
{
class NetManager
{
private static NetManager _instance = null;
private NetManager()
{
//开启一条线程处理消息队列中的消息
Thread thread = new Thread(DealWithMessage);
thread.Start();
}
public static NetManager Instance
{
get
{
if (_instance == null)
{
_instance = new NetManager();
}
return _instance;
}
}
//消息的广播:需要使用List容器存储与客户端建立的连接
private static List<ClientPeer> clientList = new List<ClientPeer>();
//消息队列
Queue<ClientMessage> messageQueue = new Queue<ClientMessage>();
public void AddClient(ClientPeer client)
{
clientList.Add(client);
}
public void RemoveClient(ClientPeer client)
{
clientList.Remove(client);
}
//广播消息
public void BoardCastMessage(ProtocolEnum messageId, string message,ClientPeer client = null)
{
for (int i = 0; i < clientList.Count; i++)
{
if (client!=null&& clientList[i] == client)
{
continue;
}
clientList[i].SendMessage(messageId,message);
}
}
public void BoardCastMessage(byte[] message, ClientPeer client = null)
{
for (int i = 0; i < clientList.Count; i++)
{
if (client != null && clientList[i] == client)
{
continue;
}
clientList[i].SendMessage(message);
}
}
public void SendMessage(byte[] message,ClientPeer client)
{
client.SendMessage(message);
}
public void SendMessage(ProtocolEnum messageId,string message, ClientPeer client)
{
client.SendMessage(messageId,message);
}
public void AddMessage(byte[] msgArr,ClientPeer clientPeer)
{
SocketMessage socketMessage = SocketMessage.Parse(msgArr);
messageQueue.Enqueue(new ClientMessage(clientPeer, socketMessage));
}
private void DealWithMessage()
{
while (true)
{
if (messageQueue.Count > 0)
{
ClientMessage clientMessage = messageQueue.Dequeue();
switch (clientMessage.message.messageId)
{
case ProtocolEnum.loginReq:
break;
case ProtocolEnum.loginRep:
break;
case ProtocolEnum.registerReq:
break;
case ProtocolEnum.registerRep:
break;
case ProtocolEnum.updateChat:
BoardCastMessage(ProtocolEnum.updateChat, clientMessage.message.message,clientMessage.client);//不给自己发消息
Console.WriteLine(clientMessage.message.message);
break;
default:
break;
}
}
}
}
}
}
ClientPeer类:
using Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace AsyncChatServer
{
class ClientPeer
{
Socket clientSocket = null;
static byte[] msgArr = new byte[1024];
internal ClientPeer(Socket clientSocket)
{
this.clientSocket = clientSocket;
clientSocket.BeginReceive(msgArr,0,msgArr.Length, SocketFlags.None, AsyncReceive, clientSocket);
}
internal void AsyncReceive(IAsyncResult ar)
{
try
{
Socket clientSocket = ar.AsyncState as Socket;
int length = clientSocket.EndReceive(ar);
if (clientSocket == null)
{
clientSocket.Close();
NetManager.Instance.RemoveClient(this);
return;
}
//string message = Encoding.UTF8.GetString(msgArr,0,length);
//Console.WriteLine(message);
//广播
//NetManager.Instance.BoardCastMessage(message, this);
byte[] arr = new byte[length];
Array.Copy(msgArr, 0, arr, 0, length);
NetManager.Instance.AddMessage(arr,this);
clientSocket.BeginReceive(msgArr, 0, msgArr.Length, SocketFlags.None, AsyncReceive, clientSocket);
}
catch (Exception e)
{
clientSocket.Close();
NetManager.Instance.RemoveClient(this);
Console.WriteLine(e.Message);
return;
}
}
public void SendMessage(byte[] message)
{
clientSocket.Send(message);
}
public void SendMessage(ProtocolEnum messageId , string message)
{
SocketMessage msg = new SocketMessage(messageId, message);
clientSocket.Send(msg.PackMessage());
}
}
}
ClientMessage类:
using Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AsyncChatServer
{
/// <summary>
///
/// </summary>
class ClientMessage
{
public ClientPeer client;
public SocketMessage message;
public ClientMessage(ClientPeer client, SocketMessage socketMessage)
{
this.client = client;
this.message = socketMessage;
}
}
}
客户端:
ChatPanel脚本:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class ChatPanel : MonoBehaviour
{
StringBuilder stringBuilder=new StringBuilder("");
TMP_InputField TMP_input;
Button button;
InputField inputfield;
Text content;
//获取相关的组件
private void Awake()
{
TMP_input = transform.Find("InputField").GetComponent<TMP_InputField>();
content = GameObject.Find("Content").GetComponent<Text>();
button = transform.Find("Btn_Send").GetComponent<Button>();
button.onClick.AddListener(OnSend);
NetManager.Instance.updateChat+= UpdateContent;
Debug.LogError(NetManager.Instance);
}
// Start is called before the first frame update
void Start()
{
}
private void OnSend()
{
if (string.IsNullOrEmpty(TMP_input.text))
{
return;
}
Debug.Log(TMP_input.text);
//将内容发送给服务器
NetManager.Instance.SendMessageToServer(Protocol.ProtocolEnum.updateChat,TMP_input.text);
//刷新界面
UpdateContent(TMP_input.text);
//将输入框清空
TMP_input.text = "";
}
public void UpdateContent(string message)
{
stringBuilder.AppendLine(message);
content.text = stringBuilder.ToString();
}
// Update is called once per frame
void Update()
{
}
}
NetManager脚本:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
using Protocol;
public class NetManager : MonoBehaviour
{
//单例
private static NetManager _instance = null;
public static NetManager Instance
{
get
{
return _instance;
}
}
// Start is called before the first frame update
//客户端连接服务器
//1.连接到服务器
//2.接受服务器的消息,并处理
//3.向服务器发送消息
byte[] msgArr = new byte[1024];
Socket clientSocket = null;
//消息队列,用于处理消息
Queue<SocketMessage> messageQueue = new Queue<SocketMessage>();
//public delegate void updateClientMsgDel(string message);
//public updateClientMsgDel del;
public event Action<string> updateChat;
private void Awake()
{
_instance = this;
}
void Start()
{
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSocket.Connect(new IPEndPoint(IPAddress.Parse(Protocol.ProtocolConfig.ip), Protocol.ProtocolConfig.port));
Debug.Log("客户端开始连接服务器!");
try
{
clientSocket.BeginReceive(msgArr, 0, msgArr.Length, SocketFlags.None, AsyncReceive, clientSocket);
}
catch (System.Exception e)
{
Debug.Log(e.Message);
}
}
//接受服务器的消息
private void AsyncReceive(IAsyncResult ar)
{
Socket clientSocket = ar.AsyncState as Socket;
if (clientSocket == null)
{
return;
}
int length = clientSocket.EndReceive(ar);
byte[] Arr = new byte[length];
Array.Copy(msgArr, 0, Arr, 0, length);
SocketMessage message = SocketMessage.Parse(Arr);
//string message = Encoding.UTF8.GetString(msgArr, 0, length);//接受的消息,思考为啥不在这个函数里面处理消息
//异步的本质是一条多线程,很多Unity的API没有办法在支线程中使用
//updateChat(message.message);
messageQueue.Enqueue(message);
clientSocket.BeginReceive(msgArr, 0, msgArr.Length, SocketFlags.None, AsyncReceive, clientSocket);
}
public void SendMessageToServer(ProtocolEnum messageId, string message)
{
SocketMessage msg = new SocketMessage(messageId, message);
clientSocket.Send(msg.PackMessage());
}
// Update is called once per frame
void Update()
{
if (messageQueue.Count>0)
{
SocketMessage message = messageQueue.Dequeue();
switch (message.messageId)
{
case ProtocolEnum.loginRep:
break;
case ProtocolEnum.registerRep:
break;
case ProtocolEnum.updateChat:
updateChat(message.message);
break;
default:
break;
}
}
}
}
最后运行:
网络通讯day02
完整项目学习视频源文件:文章来源:https://www.toymoban.com/news/detail-463224.html
链接:https://张pan.baidu.com/s三/1ql3j4JXNboVKYzGn6_80tA (把张三去掉)
提取码:wwww
--来自百度网盘超级会员V6的分享文章来源地址https://www.toymoban.com/news/detail-463224.html
到了这里,关于Week 08-day02-Unity网络通讯之聊天室的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!