嗯,其实和上一篇在代码上没有多大的出入,服务器做了一点小的功能添加,就是自动给连接的客户端分配一个名字(以后肯定是客户端自行注册接入到数据库),下面是代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;//引用命名空间
using System.Net;
using System.Threading;
namespace MySever
{
class Program
{
public static List<ClientSocket> ClientSocketList = new List<ClientSocket>();
private static int clientIndex = 0;//连接服务器的客户端索引
public static string clientName;//为连接的客户端分配名字
static void Main(string[] args)
{
Socket severSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
severSocket.Bind(new IPEndPoint(IPAddress.Parse("192.168.0.100"), 1314));
severSocket.Listen(100);
Console.WriteLine("服务器已经启动");
while(true)//表示一直接收客户端,每接收一个客户端暂停住等待下一个客户端连接
{
Socket socket = severSocket.Accept();
clientIndex += 1;//每连接一个客户端索引增一
clientName = "客户端" + clientIndex;
socket.Send(Encoding.UTF8.GetBytes(clientName));//把客户端名字发送给客户端
Console.WriteLine(clientName+ " :已经连接");
ClientSocket clientSocket = new ClientSocket(socket);//实例化一个控制客户端的ClietSocket,在ClientSocket的构造函数里面进行数据的控制
ClientSocketList.Add(clientSocket);//每连接一个客户端,就加入到集合
}
}
/// <summary>
/// 消息的广播,发布到每个客户端
/// </summary>
/// <param name="message"></param>
public static void BroadcastMessage(string message)
{
List<ClientSocket> breakConnect = new List<ClientSocket>();//表示断开连接的客户端
foreach (var item in ClientSocketList)//遍历所有连接了服务器的客户端
{
if (item.Connected)//如果客户端还在连接
{
item.SendMessage(message);//就向客户端发送消息
}
else
{
breakConnect.Add(item);//否则就加入到断开连接的集合里
}
}
foreach (var item in breakConnect)//遍历断开连接的客户端
{
Console.WriteLine("duankai");
ClientSocketList.Remove(item);//从连接的客户端里移除断开连接的客户端
}
}
}
}
ClientSocket类和之前的完全一样就不贴了。然后客户端代码也基本没有变化:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Net.Sockets;
using System.Net;
using System;
using System.Text;
using System.Threading;
public class UnityClient : MonoBehaviour
{
public Text ShowText;
private string _message;
public InputField Input;
private Socket _clientSocket;
private byte[] _buffer = new byte[1024];
private string _clientName;
private void Start()
{
_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_clientSocket.Connect(new IPEndPoint(IPAddress.Parse("192.168.0.100"), 1314));
RecieveName();//获取自身的名字
Thread t = new Thread(RecieveMessage);
t.Start();
}
private void Update()
{
if (_message != null && _message != "")//表示接收到的消息不为空
{
ShowText.text = ShowText.text + _message + "\n";
_message = "";//接收之后把用来接收的消息设为空字符串
}
}
public void SendMessageOptions()
{
string message = "<Color=red>"+_clientName+"</Color>" + ":" + Input.text;
_clientSocket.Send(Encoding.UTF8.GetBytes(message));
Input.text = "";
}
public void RecieveMessage()
{
while (true)
{
if (_clientSocket.Connected == false) break;
int count = _clientSocket.Receive(_buffer);
_message = Encoding.UTF8.GetString(_buffer, 0, count);
}
}
public void RecieveName()
{
int length = _clientSocket.Receive(_buffer);
_clientName = Encoding.UTF8.GetString(_buffer, 0, length);
}
public void OnDestroy()
{
string message = _clientName + ":断开连接";
_clientSocket.Send(Encoding.UTF8.GetBytes(message));
}
}
连接服务器,接收发送消息基本就是这样的一套流程,Unity上面的设置也很简单:
为InputField组件添加完成输入的事件,就是上面的SendMeaasgeOptions:
还做了一个滑动条的效果:
Content就是要显示在面板的信息,记得加上以便自适应大小。
下面来看看效果,首先运行服务器,然后打开两个客户端:
然后客户端1(Unity)发送消息:
客户端2(发布的)发送消息:
客户端2颜色没变(打包后在Unity修改了没有重新发布)。
基本效果就是这个样子了,感觉有点低级,嗯继续学习吧,下篇开始不使用循环等待客户端,使用BeginRecept()方法。
欢迎加群:4364930讨论。