本小白刚接触到socket编程这一块,模仿着写了一个多人在线聊天室,也算是对这个模块有了初步认识吧,写这篇博客一来是在日后能够再温习一下,二来是想给更多小白一个参考学习的详细案例,三来也是对自己学习过程的一个笔记总结吧!好了,话不多说,直接上成果!
演示视频
unity制作聊天室成果展示视频
工具
- Visual Studio 2017
- Unity 2017
- NGUI插件
1.服务器端
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace TCP_Unity_Server
{
class Program
{
//用于存储接收到的每一个 与客户端交互对象
static List<Client> clientList = new List<Client>();
//将一个客户端发出到服务器的消息,发送给所有的客户端(包括他自己)
public static void BroadcastMessage(string message)//message就是服务器接收到的消息
{
var notConnectedList = new List<Client>();//存放所有断开连接的
foreach (var client in clientList)//遍历之前所有连接成功的 与客户端交互对象
{
//判断 与客户端交互对象 是否与服务断开连接
if (client.Connected)//处于连接状态
{
client.SendMessage(message);//与客户端交互对象 向该客户端发送该消息
}
else//处于断开状态
{
notConnectedList.Add(client);//断开了,就不需要向其发送消息了
}
}
foreach (var temp in notConnectedList)//将断开的 与客户端交互对象删掉
{
clientList.Remove(temp);
}
}
static void Main(string[] args)
{
//1.创建sicket
Socket tcpServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//2.绑定ip跟端口号 192.168.0.103(本机的ip地址,端口号设置一个四位数的即可)
//提供internet协议的ip地址
IPAddress ipaddress = new IPAddress(new byte[] { 192, 168, 0, 103 });
//IPEndPoint是对ip+端口做了一层封装的类
EndPoint point = new IPEndPoint(ipaddress, 7788);
//向操作系统申请一个可用的ip跟端口号 用来做通信(判断上面写ip、端口的是否用)
tcpServer.Bind(point);
//3.开始监听(等待客户端连接)
//参数是最大连接数,表示该服务器能连接多少台用户端,我设置的为5
tcpServer.Listen(5);
//这里是在控制台提示,服务器是否在运行
Console.WriteLine("server running...");
//这里做了一个死循环,因为客户端不止一个,一直要接收客户端的连接请求
while (true)
{
//使用返回的socket(clientSocket)跟客户端做通讯 (后面将其称为 与客户端交互对象)
Socket clientSocket = tcpServer.Accept();
//这段程序时暂停当前线程,直到有一个客户端连接过来,再进行下面的脚本操作
//这里是在控制台提示,服务器是否在运行,表示有客户端连接进来了
Console.WriteLine("a client is connected!");
//把接收到的客户端对象 放到Client类(用来跟看客户端进行通讯)里面处理
Client client = new Client(clientSocket);//一个client 就表示一个 与客户端交互对象
//将客户端对象添加进集合中
clientList.Add(client);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace TCP_Unity_Server
{
//用来跟客户端做通信 (与客户端交互对象)
class Client
{
private Socket clientSocket;//与客户端交互对象
private Thread t;//线程
private byte[] data = new byte[1024];//数据容器
public Client(Socket s)
{
//clientSocket就是 与客户端交互对象
clientSocket = s;
//启动一个线程 处理客户端的数据接收
t = new Thread(ReceiveMessage);//创建一个线程用于处理ReceiveMessage
//开始执行
t.Start();
}
private void ReceiveMessage()
{
while (true)//设置为死循环,是因为这个线程:服务器一直会与客户端进行通讯
{
//在接收前,判断一下socket连接是否断开(与客户端交互对象 的状态是否处于连接)
//if (clientSocket.Connected==false)
if (clientSocket.Poll(10,SelectMode.SelectRead))//10毫秒的判断时间是否断开连接了
{
clientSocket.Close();//如果断开了连接,那么就要关闭与客户端的通讯(与客户端交互对象),也就是与这台客户端的通讯线程完成了
break;//跳出循环,终止线程执行
}
//返回值表示接收了多少字节的数据,
//clientSocket.Receive(data)用于接收客户端发送过来的数据,数据需要接收
//用一个1024字节大小的容器data接收
int length = clientSocket.Receive(data);//与客户端交互对象 接收到的数据
//将接受到的data数据,只把从索引0开始的length个字节转化string
string message = Encoding.UTF8.GetString(data,0,length);
//TODO:接收到数据的时候 要把这个数据分发到客户端
//广播这个消息
Program.BroadcastMessage(message);
//在控制台输出服务器接收到的消息
Console.WriteLine("收到了消息:"+message);
}
}
public void SendMessage(string message)
{
//将将需要发送的message数据,转化为byte字节形式存入byte数组中
byte[] data = Encoding.UTF8.GetBytes(message);
clientSocket.Send(data);//与客户端交互对象 将这个消息message 发送给这个客户端
}
public bool Connected//判断 与客户端交互对象 是否处于连接状态
{
get { return clientSocket.Connected; }
}
}
}
2.客户端(Uinty)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
public class chatMessage : MonoBehaviour {
public string ipaddress = "192.168.0.103";//与服务器ip保持一样
public int port = 7788;//端口号
public UIInput textInput;//输入框(用的NGUI构造)
public UILabel chatLable;//Lable(用的NGUI构造)
private Socket clientSocket;//socket,定义为全局,作用于所有方法
private Thread t;//线程,定义为全局,作用于所有方法
private byte[] data = new byte[1024];//数据容器,定义为全局,作用于所有方法
private string message = "";//用来接收服务器放松过来的消息 消息容器 ,定义为全局,作用于所有方法
// Use this for initialization
void Start () {
ConnectToServer();//一运行程序,就会去连接服务器
}
// Update is called once per frame
void Update () {
if (message!=null && message!="")
{
chatLable.text += "\n" + message;
message = "";
}
}
void ConnectToServer()//连接服务器
{
//创建socket对象
clientSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
//跟服务器建立连接
clientSocket.Connect(new IPEndPoint(IPAddress.Parse(ipaddress), port));
//创建一个新的线程 用来接收消息
t = new Thread(ReceiveMessage);
t.Start();
}
//这个线程方法 用来循环接收数据
void ReceiveMessage()//用来接收服务器发送过来的消息
{
//死循环,因为客户端一经连接,就始终处于交互状态,除非断开
while (true)
{
if (clientSocket.Connected == false)//判断是否断开连接
break;//断开则跳出
//返回值表示接收了多少字节的数据,
int length = clientSocket.Receive(data);
//将接受到的data数据,只把从索引0开始的length个字节转化为string
message = Encoding.UTF8.GetString(data, 0, length);
}
}
//用于向服务器发送消息
void SendMessage(string message)
{
//将将需要发送的message数据,转化为byte字节形式存入byte数组中
byte[] data = Encoding.UTF8.GetBytes(message);
clientSocket.Send(data);//向服务器发送消息
}
public void OnSendButtonClick()//这个是为按钮做的方法(在unity中,为button添加on click事件)
{
string value = textInput.value;//获取输入框里信息
SendMessage(value);//向服务器发送消息
textInput.value = "";//发送后清空输入框
}
//void OnDestory()
//{
// clientSocket.Shutdown(SocketShutdown.Both)//既不接受也不发送
// clientSocket.Close();//关闭socket
//}
}
源码、插件、聊天室应用程序分享
链接:https://pan.baidu.com/s/1Ufqgl1jKcSds6sWDjyDHIw
提取码:miuu