unity给服务器发消息,Unity中的聊天功能(异步Socket)

实现聊天功能分为两部分:服务端,客户端。话不多说,上代码。

1. 服务端 (用VS写的控制台程序),主要实现异步通信,及连接池

1.1 ConnectClient (客户端连接类)

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Net;

using System.Net.Sockets;

namespace TestSocketServer

{

///

/// 客户端连接对象类

///

class ConnectClient

{

//缓冲区大小+

public const int BUFFER_SIZE = 1024;

public Socket socket;

//是否使用

public bool isUse = false;

//缓冲区

public byte[] readBuff = new byte[BUFFER_SIZE];

//数据大小

public int bufferCount;

//构造

public ConnectClient()

{

readBuff = new byte[BUFFER_SIZE];

}

///

/// 初始化数据

///

///

public void Init(Socket soc)

{

this.socket = soc;

isUse = true;

bufferCount = 0;

}

///

/// 缓冲区剩余字节空间

///

///

public int BufferRemain()

{

return BUFFER_SIZE - bufferCount;

}

///

/// 获取socket连接地址

///

///

public string Address()

{

if (!isUse)

{

return null;

}

else

{

return socket.RemoteEndPoint.ToString();

}

}

///

/// 关闭连接

///

public void Close()

{

if (!isUse)

{

return;

}

else

{

Console.WriteLine(Address() + " [ 断开连接 ]");

socket.Close();

isUse = false;

}

}

}

}

1.2 SocketServer (服务端控制类)

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Net;

using System.Net.Sockets;

namespace TestSocketServer

{

///

/// 服务器类

///

class SocketServer

{

//监听socket对象

public Socket listenSocket;

//客户端连接池

public ConnectClient[] clientList;

//容纳客户端数量

public int maxClient = 50;

///

/// 从连接池中 获取客户端连接对象 ,如果列表中以满 则获取失败

///

///

public int GetIndex()

{

//如果连接池为空 则新建连接池 返回第一个连接对象

if (clientList == null)

{

clientList = new ConnectClient[maxClient];

clientList[0] = new ConnectClient();

return 0;

}

else

{

//遍历连接池 , 返回未使用连接对象的索引

for (int i = 0; i < clientList.Length; i++)

{

if (clientList[i] == null)

{

clientList[i] = new ConnectClient();

return i;

}

else if (clientList[i].isUse == false)

{

return i;

}

}

//如果都有对象且在使用中,则返回-1. 代表获取失败

return -1;

}

}

//接收回调

private void AcceptCallBack(IAsyncResult ar)

{

try

{

Socket socket = listenSocket.EndAccept(ar);

int index = GetIndex();

if (index< 0)

{

socket.Close();

Console.WriteLine("服务器连接已满,请稍候再试");

}

else

{

ConnectClient client = clientList[index];

client.Init(socket);

client.socket.BeginReceive(client.readBuff, client.bufferCount, client.BufferRemain(), SocketFlags.None, ReceiveCallBack,client);

Console.WriteLine("客户端连接成功 = " + client.Address());

}

//重新开始异步接收请求

listenSocket.BeginAccept(AcceptCallBack, null);

}

catch (Exception e)

{

Console.WriteLine("客户端请求异常! Exception = " + e.Message);

}

}

//返回回调

private void ReceiveCallBack(IAsyncResult ar)

{

ConnectClient client = (ConnectClient)ar.AsyncState;

try

{

int count = client.socket.EndReceive(ar);

//断开连接

if (count <= 0)

{

Console.WriteLine("断开连接 = " + client.Address());

client.Close();

}

else

{

string receiveString = System.Text.Encoding.UTF8.GetString(client.readBuff, 0, count);

Console.WriteLine("接收 " + client.Address() + " 的数据 = " + receiveString);

byte[] sendBytes = System.Text.Encoding.UTF8.GetBytes(client.Address() + " : " + receiveString);

//广播信息

for (int i = 0; i < clientList.Length; i++)

{

if (clientList[i] == null)

{

continue;

}

if (clientList[i].isUse == false)

{

continue;

}

clientList[i].socket.Send(sendBytes);

Console.WriteLine("广播 " + client.Address() + " 的数据 给 " + clientList[i].Address());

}

}

//继续接收数据

client.socket.BeginReceive(client.readBuff, client.bufferCount, client.BufferRemain(), SocketFlags.None, ReceiveCallBack, client);

}

catch (Exception e)

{

Console.WriteLine("[接收数据异常] client = " + client.Address());

Console.WriteLine(" Execption = " + e.Message);

client.Close();

}

}

///

/// 开启服务

///

/// 主机地址

/// 端口

/// 容纳客户端数量 (默认50)

public void Start(string host , int port , int maxClient = 50)

{

//初始化连接池

this.maxClient = maxClient;

clientList = new ConnectClient[this.maxClient];

listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

IPAddress ipa = IPAddress.Parse(host);

IPEndPoint ipe = new IPEndPoint(ipa, port);

listenSocket.Bind(ipe);

listenSocket.Listen(maxClient);

//开启异步接收连接

listenSocket.BeginAccept(AcceptCallBack, null);

Console.WriteLine("服务器启动成功!");

}

}

}

启动服务端:

static void Main(string[] args)

{

Console.WriteLine("请输入服务端IP地址:");

string host = Console.ReadLine();

Console.WriteLine("请输入服务端端口号:");

string port = Console.ReadLine();

SocketServer server = new SocketServer();

//只是本机测试,可以写127.0.0.1 , 但是要让其他机器连接的话,要写实际ip地址

//server.Start("192.168.0.171", 1234);

server.Start(host, int.Parse(port));

while (true)

{

string write = Console.ReadLine();

switch (write)

{

case "quit":

return;

}

}

}

2. 客户端,聊天Demo 及Socket通信。

场景界面如下:

b47e85d68dd3

图片.png

功能控制脚本:

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using System.Net.Sockets;

using System.Net;

using UnityEngine.UI;

using System;

public class TestClient : MonoBehaviour {

private Socket m_Socket;

public InputField HostField;

public InputField PortField;

public InputField MessageField;

public InputField LinkMessageField;

public InputField ReceiveFiled;

private byte[] readBuff = new byte[1024];

private string reveString; //接收的字符数据

private bool isReceived = false; //数据接收完成

// Use this for initialization

void Start ()

{

//设置后台运行,数据就会立马同步更新。否则其他客户端发送一条消息,服务端进行广播,但是Unity进程被挂起了,就无法实时更新

Application.runInBackground = true;

}

public void LinkServer()

{

m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

try

{

m_Socket.Connect(HostField.text, int.Parse(PortField.text));

LinkMessageField.text = "连接成功-----" + m_Socket.LocalEndPoint.ToString();

}

catch (Exception)

{

LinkMessageField.text = "连接失败!!";

throw;

}

m_Socket.BeginReceive(readBuff, 0, 1024, SocketFlags.None, ReceiveCallBack, null);

}

public void SendMessageToServer()

{

try

{

byte[] sendBytes = System.Text.Encoding.UTF8.GetBytes(MessageField.text);

m_Socket.Send(sendBytes);

}

catch (Exception)

{

throw;

}

}

//服务器返回回调

private void ReceiveCallBack(IAsyncResult ar)

{

try

{

int count = m_Socket.EndReceive(ar);

reveString = System.Text.Encoding.UTF8.GetString(readBuff, 0, count);

isReceived = true;

//之所以不直接在这里赋值,是因为线程问题,会报错,该回调不是在unity主线程中执行的,所以赋值放在update中

//if (ReceiveFiled.text.Length > 500)

//{

// ReceiveFiled.text = "";

//}

//ReceiveFiled.text += reveString + '\n';

//继续接收返回信息

m_Socket.BeginReceive(readBuff, 0, 1024, SocketFlags.None, ReceiveCallBack, null);

}

catch (Exception)

{

reveString = m_Socket.LocalEndPoint.ToString() + "连接断开";

isReceived = true;

m_Socket.Close();

throw;

}

}

private void Update()

{

if (isReceived)

{

if (ReceiveFiled.text.Length > 500)

{

ReceiveFiled.text = "";

}

ReceiveFiled.text += reveString + '\n';

isReceived = false;

}

}

}

运行效果如下:

b47e85d68dd3

图片.png

最后:

以上纯属个人总结,如有不对或者更好的方法,欢迎指正,交流。

工程文件链接 : https://github.com/IongX/Unity_Socket

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值