整体流程如下:
- 创建一个新的C#控制台应用程序项目用于编写服务器端代码
- 新建一个Unity项目,创建一个C#脚本来编写客户端代码
- 另外新建一个脚本用于在主线程中执行任务,以便更新UI
- UI搭建:InputField、Button、Scroll View、还有一个Text预制体用于显示文本内容
- 添加脚本并赋值
最终效果:
【unity+socket】实现聊天室
开始制作
1.编写服务器端代码
// 聊天服务器类,包含启动服务器、处理客户端连接和消息广播的方法
private TcpListener listener;
private List<TcpClient> clients = new List<TcpClient>();
// 启动服务器方法,接受一个端口号作为参数
public void Start(int port)
{
listener = new TcpListener(IPAddress.Any, port);
listener.Start();
Console.WriteLine("Server started on port " + port);
while (true)
{
TcpClient client = listener.AcceptTcpClient();
clients.Add(client);
Console.WriteLine("Client connected!");
Thread clientThread = new Thread(HandleClient);
clientThread.Start(client);
}
}
// 处理客户端连接的方法,接受一个对象作为参数
private void HandleClient(object obj)
{
TcpClient client = (TcpClient)obj;
NetworkStream stream = client.GetStream();
while (true)
{
byte[] buffer = new byte[256];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
if (bytesRead == 0)
{
clients.Remove(client);
client.Close();
Console.WriteLine("Client disconnected");
break;
}
string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine("Received: " + message);
BroadcastMessage(message, client);
}
}
// 广播消息方法,接受消息和发送者作为参数
private void BroadcastMessage(string message, TcpClient sender)
{
foreach (TcpClient client in clients)
{
if (client != sender)
{
NetworkStream stream = client.GetStream();
byte[] buffer = Encoding.UTF8.GetBytes(message);
stream.Write(buffer, 0, buffer.Length);
}
}
}
}
// 程序主类,包含程序入口点
class Program
{
static void Main(string[] args)
{
ChatServer server = new ChatServer();
server.Start(5000);
}
2.客户端代码
public InputField messageInput;
public Button sendButton;
public ScrollRect scrollView;
public GameObject textPrefab; // 预制体,包含Text组件
private TcpClient client;
private NetworkStream stream;
private Thread receiveThread;
void Start()
{
sendButton.onClick.AddListener(SendMessage);
ConnectToServer("127.0.0.1", 5000);
}
void ConnectToServer(string ip, int port)
{
client = new TcpClient(ip, port);
stream = client.GetStream();
receiveThread = new Thread(ReceiveMessages);
receiveThread.Start();
}
void ReceiveMessages()
{
while (true)
{
byte[] buffer = new byte[256];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
if (bytesRead == 0)
{
Debug.Log("Server disconnected");
break;
}
string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
AppendMessage(message);
}
}
void AppendMessage(string message)
{
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
GameObject newText = Instantiate(textPrefab, scrollView.content);
newText.GetComponent<Text>().text = message;
Canvas.ForceUpdateCanvases();
scrollView.verticalNormalizedPosition = 0f;
Canvas.ForceUpdateCanvases();
});
}
public void SendMessage()
{
string message = messageInput.text;
byte[] buffer = Encoding.UTF8.GetBytes(message);
stream.Write(buffer, 0, buffer.Length);
messageInput.text = "";
// 显示发送的消息
AppendMessage(message);
}
void OnApplicationQuit()
{
if (receiveThread != null && receiveThread.IsAlive)
{
receiveThread.Abort();
}
if (client != null && client.Connected)
{
client.Close();
}
}
3.更新UI代码
private static readonly Queue<System.Action> _executionQueue = new Queue<System.Action>();
private static UnityMainThreadDispatcher _instance = null;
public static UnityMainThreadDispatcher Instance()
{
if (_instance == null)
{
GameObject go = new GameObject("UnityMainThreadDispatcher");
_instance = go.AddComponent<UnityMainThreadDispatcher>();
DontDestroyOnLoad(go);
}
return _instance;
}
void Update()
{
lock (_executionQueue)
{
while (_executionQueue.Count > 0)
{
_executionQueue.Dequeue().Invoke();
}
}
}
public void Enqueue(System.Action action)
{
lock (_executionQueue)
{
_executionQueue.Enqueue(action);
}
}
4.搭建UI框架
ps:这里我搭建的比较简洁,如有需要可以根据自己的审美进行搭建
大致如图
需要注意的是给Scroll View的Content添加两个组件用于多个文本更好的显示
同时也要给Text预制体添加上面的第二个组件用于文本全面地显示 。
5.添加脚本并赋值
-
在Hierarchy窗口中,创建一个空的GameObject,将客户端脚本添加上,并将Input Field、Button、Scroll View和Text预制体分别拖到客户端脚本的相应字段中。
-
在Hierarchy窗口中,创建一个空的GameObject,并将
用于更新UI
脚本附加到该GameObject上。
最后
-
启动服务器端应用程序。
-
在Unity中运行项目,输入消息并点击发送按钮,消息将会显示在Scroll View中。