C#网络编程学习(3)---使用Tcp和Unity创建本地聊天室的小案例
使用Tcp协议实现最简单的本地局域网聊天
1、思路
服务器
- 先用C#网络编程学习(1)---Socket之Tcp协议的简单使用中方法写可接收多个客户端的连接代码。
- 另外写一个类Client专门处理连接的客户端clientSocket。
- 在主类中用List
存放所有连接的客户端。。 - 在Client中给出接收信息(线程),发送信息,是否处于连接状态方法。
- 在主类中写广播方法(向所有客户端发送信息)
Unity客户端UI
Unity客户端代码
- Unity空物体ChatManager中绑定脚本ChatManager
- 游戏开始时连接服务器
- 点击按钮事件触发Send()发送数据方法
- 接收广播消息的方法(线程).
2、服务器端
/// <summary>
/// 主类中写服务器信息
/// </summary>
class Program
{
//创建一个集合记录所有连接的客户端,当广播消息时,向连接的全体客户端发送消息
private static List<Client> clientList = new List<Client>();
static void Main(string[] args)
{
Socket tcpServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
tcpServer.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.2"), 7788));
tcpServer.Listen(100);
Console.WriteLine("server running");
while (true) //用while接收多个客户端连接
{
Socket tcpClient = tcpServer.Accept();
Console.WriteLine("a client is connected");
//因为不仅需要while接收多个客户端,每个客户端也可以一直发送消息。所以单独写个类来控制客户端比较直观方便。
Client client = new Client(tcpClient);
clientList.Add(client);
}
}
//广播消息 (就是向所有客户端发送消息)
public static void BroadcastMessage(string message)
{
List<Client> notConnectedList = new List<Client>(); //获得所有断开连接的客户端
//遍历list集合,向所有客户端发送消息
foreach (var client in clientList)
{
if (client.Connected)
client.SendMessage(message);
else
{
notConnectedList.Add(client);
}
}
//把所有断开连接的客户端移除
foreach (var temp in notConnectedList)
{
clientList.Remove(temp);
}
}
}
/// <summary>
/// Client类用来和客户端做通信
/// </summary>
class Client
{
private Socket clientSocket;
private Thread t;
private byte[] data = new byte[1024]; //这个是一个数据容器
public Client(Socket s)
{
clientSocket = s;
//启动一个线程 处理客户端的接收
t = new Thread(ReceiveMessage);
t.Start();
}
//接收客户端的消息
private void ReceiveMessage()
{
//循环一直接收客户端的数据
while (true)
{
//在接收数据之前,判断socket连接是否断开
if (clientSocket.Poll(10, SelectMode.SelectRead))
{
clientSocket.Close();
break; //跳出循环,中止线程的执行
}
int length = clientSocket.Receive(data);
string message = Encoding.UTF8.GetString(data, 0, length);
//消息的广播,要放在Main里面写,因为在Main中存着所有连接的客户端
Program.BroadcastMessage(message);
Console.WriteLine("收到了消息" + message);
}
}
//向所有客户端发送消息
public void SendMessage(string message)
{
byte[] data = Encoding.UTF8.GetBytes(message);
clientSocket.Send(data);
}
//判断客户端服务器是否还连接,不连接将在Main里面删去
public bool Connected
{
get { return clientSocket.Connected; }
}
}
3、客户端
public class ChatManager : MonoBehaviour
{
private string ipAddress = "192.168.1.2";
private int port = 7788;
private Socket clientSocket;
public InputField textInput; //用户输入框
//接收服务器数据
private Thread t;
private byte[] data = new byte[1024];
private string receiveMessages = "";
public Text chatText; //用户聊天框
private void Start()
{
ConnectedToServer();
}
private void Update()
{
//时刻检测当接收到数据时,receiveMessages不为空,数据加入到聊天框当中
if (receiveMessages != null && receiveMessages != "")
{
chatText.text += "\n" + receiveMessages;
receiveMessages = "";
}
}
//程序开始时连接服务器
private void ConnectedToServer()
{
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//发起连接
clientSocket.Connect(new IPEndPoint(IPAddress.Parse(ipAddress), port));
//创建一个新的线程用于接收广播消息,因为消息要一直接收的
t = new Thread(ReceiveMessage);
t.Start();
}
//发送数据
private void SendMessage(string message)
{
byte[] data = Encoding.UTF8.GetBytes(message);
clientSocket.Send(data);
}
//点击按钮触发
public void OnSendButtonClick()
{
string value = textInput.text;
SendMessage(value);
textInput.text = "";
}
//这个线程方法用于循环接收广播消息
private void ReceiveMessage()
{
while (true)
{
//与服务器断开连接时,取消线程
if (clientSocket.Connected == false)
{
break;
}
int length = clientSocket.Receive(data);
receiveMessages = Encoding.UTF8.GetString(data, 0, length);
//因为Unity中线程不允许直接操控UI组件,所以间接改变
}
}
}
4、效果
先打开VS中服务器
图1:为客户端连接时,服务器弹出连接信息,服务器可以收到客户端发送的消息
**图2**:为打开两个客户端时,一方发送消息,另一方就可以收到 ![](https://img2018.cnblogs.com/blog/1355434/201905/1355434-20190508133554525-271203991.gif)
5、百度云源码链接
链接:https://pan.baidu.com/s/1dsZNw8UQJ8BjJHejBzaOLg
提取码:3ufk