基于Socekt的Unity多人在线聊天系统

先看看效果图

基于Socekt的Unity多人在线聊天系统_第1张图片

基于Socekt的Unity多人在线聊天系统_第2张图片

以上分别是两个客户端相互通讯的情况的。


源码:https://github.com/zymix/Unity_ChatSystem


C#本身对Socket拥有着高度的封装,所以搭建这样的一个多人聊天系统是非常容易的事情。这里先提醒几点:

1.关于Unity内部编码问题,Unity在debug阶段时其编码模式是跟操作系统一致的,但是当其发布以后,由于Unity的跨平台性使其编码改变成UTF8的形式,所以无论哪个阶段,都应该注意客户端与服务器段的编码模式一致。

2.关于Scroll View的问题,想滚动条动态的改变滚动长度需要,动态修改Scroll Rect组件的Content对象的RectTransform的deltaSize


剩下的,看注释,算是比较清晰了

客户端代码

using UnityEngine;
using System.Net.Sockets;
using System;

using System.Collections.Generic;
using UnityEngine.UI;
using System.Collections;

public class ChatClient : MonoBehaviour
{
    public GameObject content;
    public InputField input;  //用于发送输入框的信息
    public InputField usernameInput;//客户端用户名
    public GameObject messageItem;//预制件的宽高
    public Button connectButton; //连接按钮

    TcpClient client;//客户端
    NetworkStream nstream;//网络数据流
    string ip = "192.168.10.5";//客户端IP
    int port = 10086;//客户端端口
    byte[] data;//客户端收发数据
    bool isConnect = false;

    List messageList;//存储接受的消息列表
    public int messagesMaxSize = 20;//存储接受的消息列表最大长度
    bool isNewMessage = false;//消息更新的标志位
    string newMessage;//接受到的最新信息
    //预制件的宽高
    float height = 0;
    float width = 0;
    void Start()
    {
        messageList = new List();
        messageList.Capacity = messagesMaxSize;

        //获取预设件的宽高
        width = messageItem.GetComponent().rect.width;
        height = messageItem.GetComponent().rect.height;

        //初始化组件
        if (content == null)
            content = transform.FindChild("Chat View/Viewport/Content").gameObject;
        if (input == null)
            input = transform.FindChild("InputField").GetComponent();
        if (usernameInput == null)
            usernameInput = transform.FindChild("UsernameInput").GetComponent();

        if (connectButton == null)
            connectButton = transform.FindChild("ConnectButton").GetComponent

简单的负责debug的提示信息类

using UnityEngine;
using System.Collections;

public class Info : MonoBehaviour {

	public static string debugStr = "";

	void OnGUI() {
		GUILayout.Label(debugStr);

	}
}


服务器端的代码

主程序

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace ChatSystem
{
    class Program
    {
        static void Main(string[] args)
        {
            //设置监听的端口号
            Console.WriteLine("请输入服务器需要监听的端口: ");
            string input = Console.ReadLine();
            int port = int.Parse(input);
            //调用方法启动服务器
            Server(port);
        }

        static void Server(int port)
        {
            //初始化服务器ip
            //IPAddress localAddress = IPAddress.Parse("127.0.0.1");
            //设置监听
            TcpListener listener = new TcpListener(IPAddress.Any, port);
            listener.Start();

            //提示信息
            Console.WriteLine("{0:HH:mm:ss}->监听端口{1}....", DateTime.Now, port);

            //循环等待客户端的连接请求
            while(true)
            {
                ChatServerHandle usr = new ChatServerHandle(listener.AcceptTcpClient());
                Console.WriteLine(usr.ip + "加入聊天室");
            }
        }

    }
}


服务器辅助类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Collections;

namespace ChatSystem
{
    class ChatServerHandle
    {
        public static Hashtable Clients = new Hashtable();//客户端连接记录表
        public TcpClient client;//客户端
        public string username;//客户端用户名

        public string ip;//客户端IP
        public int port;//客户端端口

        public byte[] data;//客户端收发数据

        bool firstConnet = true;

        public ChatServerHandle(TcpClient client)
        {
            this.client = client;
            
            //保存客户端IP和端口
            IPEndPoint ipEndPoint = client.Client.RemoteEndPoint as IPEndPoint;
            this.ip = ipEndPoint.Address.ToString();
            this.port = ipEndPoint.Port;

            //初始化收发数据
            this.data = new byte[client.ReceiveBufferSize];

            //开启异步从客户端获取消息,获取到的数据流存入data,回调ReceiveMessage方法
            client.GetStream().BeginRead(data, 0, data.Length, ReceiveMessage, null);

        }
        //向客户端发送消息
        public void SendMessage(string message)
        {
            try
            {
                NetworkStream stream;
                lock(client.GetStream())
                {
                    stream = client.GetStream();
                }
                byte[] bytes = Encoding.UTF8.GetBytes(message); //注意Unity发布后程序已UTF8编码
                stream.Write(bytes, 0, bytes.Length);
                //stream.Flush();
            }
            catch (Exception e)
            {
                Console.WriteLine("{0:HH:mm:ss}->[SendMessage]Error: {1}", DateTime.Now, e.Message);
            }
        }
        //从客户端接受到的数据,再广播给所有客户端
        public void ReceiveMessage(IAsyncResult ar)
        {
           try
            {
                int bytesRead;
                lock(client.GetStream())
                {
                    bytesRead = client.GetStream().EndRead(ar);
                }
                if (bytesRead < 1)
                {//接收不到任何数据,则删除在客户端连接记录表
                    Clients.Remove(this.ip);
                    //向所有客户端广播该用户的下线信息
                    Broadcast(""+this.username + " 于" + DateTime.Now + " 已下线....");
                    return;
                }
                else
                {  
                    string recMessage = Encoding.UTF8.GetString(data, 0, bytesRead); //注意Unity发布后程序已UTF8编码
                    if (firstConnet)
                    {   //检查是不是同一台电脑重复连接
                        if(Clients.ContainsKey(this.ip))
                            return;
                        //第一次连接,将客户端信息记录入客户端连接记录表中
                        Clients.Add(this.ip,this);
                        //获取发送的用户名信息
                        this.username = recMessage;
                        //向所有客户端广播该用户的上线信息
                        Broadcast("" + this.username + " 于" + DateTime.Now+ " 已上线....");
                        //不在是第一次连接
                        firstConnet = false;
                    }
                    else
                    {
                        //向所有客户端广播该用户发送的
                        Broadcast(DateTime.Now + " ->【"+ this.username+"】" + recMessage);
                    }
                    //Console.WriteLine(recMessage);
                }
                lock(client.GetStream())
                {
                    //再次开启异步从服务器获取消息,形成循环
                    client.GetStream().BeginRead(data, 0, client.ReceiveBufferSize, ReceiveMessage, null);
                }
            }
            catch(Exception e)
            {
                //删除连接记录
                Clients.Remove(this.ip);
                //向所有客户端广播该用户的下线信息
                Broadcast("" + this.username + " 于" + DateTime.Now + " 已下线....");

                Console.WriteLine("{0:HH:mm:ss}->[ReceiveMessage]Error: {1}", DateTime.Now, e.Message);
            }
        }

        //向所有连接到的客户端广播
        public void Broadcast(string message)
        {
            Console.WriteLine(message);
            foreach (DictionaryEntry item in Clients)
            {
                ChatServerHandle c = item.Value as ChatServerHandle;
                c.SendMessage(message);
            }
        }
    }
}


你可能感兴趣的:(Unity3D)