unity 版本 2020.0.0a12
demo 下载
服务端代码
// ========================================================
// 描述:Unity 使用Soket 实现简单的聊天demo
// 作者:qinglong
// 创建时间:2020-04-07 11:31:27
// 版 本:1.0
// ========================================================
using System.Collections.Generic;
using System.Net.Sockets;
using System.Net;
using UnityEngine;
using System;
/// <summary>
/// 服务端代码只能有一个
/// </summary>
public class MySocketServer : MonoBehaviour
{
Socket server;
List<Socket> clients = new List<Socket>();
byte[] buffer = new byte[1024];
/// <summary>
/// 创建服务器
/// </summary>
void Awake()
{
//ipv4 流式传输 tcp协议
server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 54188);
// 绑定终端
server.Bind(endPoint);
//开启监听 同一时间处理10个客户端连接
server.Listen(10);
//开启异步监听
server.BeginAccept(ReceiveClient,server);
Debug.Log("Server OK");
}
/// <summary>
/// 异步获取客户端
/// </summary>
/// <param name="_result"></param>
void ReceiveClient(IAsyncResult _result)
{
//获取服务器对象
Socket server = _result.AsyncState as Socket;
//获取客户端对象
Socket client=server.EndAccept(_result);
//再次开启异步监听
server.BeginAccept(ReceiveClient, server);
clients.Add(client);
//异步接收信息
client.BeginReceive(buffer,0,buffer.Length,SocketFlags.None, AsyncReceive,client);
}
/// <summary>
/// 异步接收消息
/// </summary>
/// <param name="result"></param>
void AsyncReceive(IAsyncResult result) {
Socket client = result.AsyncState as Socket;
//判断客户端是否断开连接 不判断 当一个客户端退出 Sever 异步会进入死循环 断电等异常退出无效
if ((client.Poll(1000, SelectMode.SelectRead) && (client.Available == 0)) || !client.Connected)
{
clients.Remove(client);
client.EndReceive(result);
Debug.Log("服务器检测到 关闭客户端");
return;
}
//检测当前只有一个客户端 提示当前客户端 对方没有上线
if (clients.Count < 2)
{
clients[0].Send(System.Text.Encoding.UTF8.GetBytes("对方没有上线"));
client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, AsyncReceive, client);
return;
}
//关闭当前异步
int len= client.EndReceive(result);
//再次异步接收信息
client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, AsyncReceive, client);
//消息的解析
byte[] buf = new byte[len];
Buffer.BlockCopy(buffer, 0, buf, 0, len);
string msg = System.Text.Encoding.UTF8.GetString(buf);
sendMassage(System.Text.Encoding.UTF8.GetBytes("对方ID:" + msg), client);
Debug.Log("对方ID"+msg);
}
/// <summary>
/// 向客户端发送消息
/// </summary>
/// <param name="buf"></param>
/// <param name="client"></param>
void sendMassage(byte[] buf, Socket client)
{
//对发送消息的客户端 服务器不再将消息再次分发到信息
for (int i = 0; i < clients.Count; i++)
{
if (clients[i]!=client)
{
clients[i].Send(buf);
}
}
}
}
客户端代码
// ========================================================
// 描述:Unity 使用Soket 实现简单的聊天demo
// 作者:qinglong
// 创建时间:2020-04-07 11:31:27
// 版 本:1.0
// ========================================================
using System.Net.Sockets;
using System.Net;
using UnityEngine;
using UnityEngine.UI;
using System;
/// <summary>
/// 客户端可以存在多个
/// </summary>
public class MySocketClient : MonoBehaviour
{
public Text Lefttext;
public Text RightText;
public ScrollRect SV;
public InputField InputField;
public Button Button;
Socket client;
byte[] buffer = new byte[1024];
int Counts = 0;
string massage;
bool createUI = false;
void Start()
{
//创建客户端
StartConnect();
//点击发送按钮 获取UI 输入信息
Button.onClick.AddListener(() => {
GetUImassage((msg) =>
{
//将UI 信息发送到服务器
sendMassage(msg);
});
});
}
/// <summary>
/// 创建服务器
/// </summary>
void StartConnect()
{
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//客户端连接客户端
client.Connect(IPAddress.Parse("127.0.0.1"), 54188);
Debug.Log(client.Connected);
//异步接收信息
client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, AsyncReceive, client);
}
/// <summary>
/// 向服务器发送消息
/// </summary>
/// <param name="msg"></param>
void sendMassage(string msg)
{
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(msg);
client.Send(buffer);
}
/// <summary>
/// 获取UI 数据
/// </summary>
/// <param name="callback"></param>
void GetUImassage(Action<string> callback)
{
Counts++;
string[] id = client.LocalEndPoint.ToString().Split(':');
string str = id[1] + " " + InputField.text;
Text rightText = Instantiate(RightText);
rightText.transform.SetParent(SV.content);
SV.content.sizeDelta = new Vector2(0, rightText.rectTransform.rect.height * Counts);
SVtoLOW();
rightText.text = "自己ID" + str;
if (callback != null) callback(str);
}
/// <summary>
/// 异步接收消息
/// </summary>
/// <param name="result"></param>
void AsyncReceive(IAsyncResult result)
{
Socket client = result.AsyncState as Socket;
int len = client.EndReceive(result);
//再次异步接收信息
client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, AsyncReceive, client);
//消息的解析
byte[] buf = new byte[len];
Buffer.BlockCopy(buffer, 0, buf, 0, len);
string msg = System.Text.Encoding.UTF8.GetString(buf);
Debug.Log("Client " + msg);
Counts++;
massage = msg;
createUI = true;
}
/// <summary>
/// 由于异步不能调用主线程 我是这么解决的
/// </summary>
private void Update()
{
if (createUI)
{
Text lefttext = Instantiate(Lefttext);
lefttext.transform.SetParent(SV.content);
SV.content.sizeDelta = new Vector2(0, lefttext.rectTransform.rect.height * Counts);
SVtoLOW();
string[] mag = massage.Split(':');
lefttext.text = mag.Length > 0? massage : "对方ID:" + massage;
createUI = false;
}
}
//设置Scroll View滑动 到最下部
void SVtoLOW()
{
float hight = SV.GetComponent<RectTransform>().rect.height;
if (SV.content.rect.height > hight)
{
float top = SV.content.rect.height - hight;
SV.content.localPosition = new Vector2(0, top);
}
}
/// <summary>
/// 关闭客户端 通知服务器 断电等异常退出无效
/// </summary>
private void OnDestroy()
{
client.Close();
Debug.Log("客户端退出");
}
}
在gethub 上找到这个脚本 UnityMainThreadDispatcher 他可以在异步中调用主线程创建text文本 等操作
下载链接下载地址
服务端没有变化
客户端代码
using System.Net.Sockets;
using System.Net;
using UnityEngine;
using UnityEngine.UI;
using System;
using System.Collections;
/// <summary>
/// 客户端可以存在多个
/// </summary>
public class MySocketClient : MonoBehaviour
{
public Text Lefttext;
public Text RightText;
public ScrollRect SV;
public InputField InputField;
public Button Button;
Socket client;
byte[] buffer = new byte[1024];
int Counts = 0;
void Start()
{
//创建客户端
StartConnect();
//点击发送按钮 获取UI 输入信息
Button.onClick.AddListener(() => {
GetUImassage((msg) =>
{
//将UI 信息发送到服务器
sendMassage(msg);
});
});
}
/// <summary>
/// 创建服务器
/// </summary>
void StartConnect()
{
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//客户端连接客户端
client.Connect(IPAddress.Parse("127.0.0.1"), 54188);
Debug.Log(client.Connected);
//异步接收信息
client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, AsyncReceive, client);
}
/// <summary>
/// 向服务器发送消息
/// </summary>
/// <param name="msg"></param>
void sendMassage(string msg)
{
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(msg);
client.Send(buffer);
}
/// <summary>
/// 获取UI 数据
/// </summary>
/// <param name="callback"></param>
void GetUImassage(Action<string> callback)
{
Counts++;
string[] id = client.LocalEndPoint.ToString().Split(':');
string str = id[1] + " " + InputField.text;
Text rightText = Instantiate(RightText);
rightText.transform.SetParent(SV.content);
SV.content.sizeDelta = new Vector2(0, rightText.rectTransform.rect.height * Counts);
SVtoLOW();
rightText.text = "自己ID" + str;
if (callback != null) callback(str);
}
/// <summary>
/// 异步接收消息
/// </summary>
/// <param name="result"></param>
void AsyncReceive(IAsyncResult result)
{
Socket client = result.AsyncState as Socket;
int len = client.EndReceive(result);
//再次异步接收信息
client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, AsyncReceive, client);
//消息的解析
byte[] buf = new byte[len];
Buffer.BlockCopy(buffer, 0, buf, 0, len);
string msg = System.Text.Encoding.UTF8.GetString(buf);
Debug.Log("Client " + msg);
Counts++;
UnityMainThreadDispatcher.Instance().Enqueue(CreateUI(msg));
}
IEnumerator CreateUI(string msg) {
Text lefttext = Instantiate(Lefttext);
lefttext.transform.SetParent(SV.content);
SV.content.sizeDelta = new Vector2(0, lefttext.rectTransform.rect.height * Counts);
SVtoLOW();
string[] mag = msg.Split(':');
lefttext.text = mag.Length > 0 ? msg : "对方ID:" + msg;
yield return null;
}
//设置Scroll View滑动 到最下部
void SVtoLOW()
{
float hight = SV.GetComponent<RectTransform>().rect.height;
if (SV.content.rect.height > hight)
{
float top = SV.content.rect.height - hight;
SV.content.localPosition = new Vector2(0, top);
}
}
private void OnDestroy()
{
client.Close();
Debug.Log("客户端退出");
}
}
新的 客户端下载地址 下载地址