TcpClient Socket通信、简单消息传递---(Unity自学笔记)

客户端:

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 ClientCore : MonoBehaviour {

    public static ClientCore instance = null;


    //建立的通讯
    private TcpClient client;
    //Stream流
    private NetworkStream stream;
    //连接是否处于活动中
    private bool __connected = false;
    public bool connected
    {
        get { return __connected; }
    }


    //接受队列
    public Queue<string> recvQueue = new Queue<string>();
    //发送队列
    public Queue<string> sendQueue = new Queue<string>();
    //缓存区大小
    private int maxBufferSize = 4096;


    //线程
    public Thread clientThread = null;
    //是否停止线程
    private volatile bool stop = false;


    //全局唯一性
    private void Awake () {
        if (instance != null)
        {
            Debug.Log("严重 : ClientCore已经存在!");
            DestroyImmediate(gameObject);
        }else
        {
            DontDestroyOnLoad(gameObject);
            instance = this;
        }
    }

    private void Start()
    {
        instance = this;

        //stop = false;
        //开启客户端主线程
        clientThread = new Thread(new ThreadStart(StartClient));
        clientThread.IsBackground = true;  //设为后台线程,伴随主线程关闭而关闭
        clientThread.Start();

    }
    //socket连接是否有效
    bool IsOpen()
    {
        return !((client.Client.Poll(1000, SelectMode.SelectRead) && (client.Client.Available == 0)) || !client.Client.Connected);
    }

    //Client线程
    void StartClient()
    {
        byte[] recvBuf = new byte[maxBufferSize];

        while (!stop)
        {
            if (!__connected)
            {
                //尝试开启一个连接
                TryConnect();
            }

            //检查发送队列
            if (sendQueue.Count > 0 && __connected)
            {
                byte[] buffer = Encoding.UTF8.GetBytes(sendQueue.Dequeue());
                stream.Write(buffer, 0, buffer.Length);
                stream.Flush();
            }

            //检查流接受数据
            if (stream.DataAvailable && __connected)
            {
                int bytesRead = stream.Read(recvBuf, 0, maxBufferSize);  //从流中获取数据,阻塞方法(如果没有数据,将阻塞线程)
                if (bytesRead > 0)
                {
                    string message = Encoding.UTF8.GetString(recvBuf);
                    Debug.Log("收到服务器消息:" + message);
                    recvQueue.Enqueue(message);
                }
            }

            //线程暂停时间(毫秒)
            Thread.Sleep(10);
        }
        //Close();
    }

    //尝试创建连接
    public void TryConnect()
    {
        CreateConnection(NetworkValue.ip, NetworkValue.port);
    }
    void CreateConnection(string host, int port)
    {
        try
        {
            client = new TcpClient();
            client.NoDelay = true;
            //client.Connect(IPAddress.Parse(host), port);
            IAsyncResult result = client.BeginConnect(IPAddress.Parse(host), port, null, null);
            __connected = result.AsyncWaitHandle.WaitOne(1000, false);

            if (__connected)
            {
                Debug.Log("连接成功!");
                client.EndConnect(result);
            }
            else
            {
                Debug.Log("连接失败!");
                client.Close();
            }
        }
        catch (SocketException ex)
        {
            __connected = false;
            Debug.Log("警告:连接出现异常--> " + ex.Message);
            client.Close();
            return;
        }
        if (__connected)
        {
            stream = client.GetStream();
        }
    }


    //将消息加入发送队列
    public static void Send(string item)
    {
        if (instance != null)
            instance.Write(item);
    }
    void Write(string item)
    {
        sendQueue.Enqueue(item);
    }

    //从接收队列获取一条消息
    public static string Recv()
    {
        if(instance!=null && instance.recvQueue.Count > 0)
        {
            return instance.recvQueue.Dequeue();
        }
        return null;
    }


    //防止程序没有正确退出
    void OnApplicationQuit()
    {
        stop = true;
        if (__connected)
        {
            __connected = false;
            stream.Close();
            client.Close();
        }
        if (clientThread != null && clientThread.IsAlive) 
        {
            clientThread.Abort();
            // 如果没有正确关闭线程,这里的Join就会阻塞,就会卡死编辑器
            // recvProcess.Join();
            Debug.Log("clientThread: " + clientThread.IsAlive);
        }
    }
    void OnDestroy()
    {
        Debug.Log("Client OnDestroy");
        OnApplicationQuit();
    }
}



服务器端:

using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;

public class ServerCore : MonoBehaviour {

    public static ServerCore instance = null;

    //服务器监听端
    private TcpListener listener = null;

    //服务器主线程
    private Thread serverThread = null;

    //最大连接数量
    private const int maxConnected = 4;

    //记载所有连接的用户
    private static  List<ClientSocket> _clients = new List<ClientSocket>();
    public static List<ClientSocket> clients { get { return _clients; } }


    //全局唯一性
    private void Awake()
    {
        if (instance != null)
        {
            Debug.Log("严重 : ServerCore已经存在!");
            DestroyImmediate(gameObject);
        }else
        {
            DontDestroyOnLoad(gameObject);
            instance = this;
        }
    }

    // Use this for initialization
    void Start () {
        instance = this;

        //开启服务器主线程
        serverThread = new Thread(new ThreadStart(StartServer));
        serverThread.IsBackground = true;   //设为后台线程,伴随主线程关闭而关闭
        serverThread.Start();
    }
	
    //服务器主线程
	void StartServer()
    {
        listener = new TcpListener(IPAddress.Parse(NetworkValue.ip), NetworkValue.port);
        Debug.Log("服务器已开启: ip-" + NetworkValue.ip + "     port-" + NetworkValue.port);
        listener.Start();

        //侦测连接的客户端
        while (true)
        {
            TcpClient tcpclient = listener.AcceptTcpClient();//已连接的客户端,阻塞方法
            Debug.Log("一个新用户! Client : " + tcpclient.Client.RemoteEndPoint);

            if (_clients.Count < maxConnected)
            {
                //建立玩家连接类(开启每一个玩家的单独线程)
                ClientSocket client = new ClientSocket(tcpclient);
                _clients.Add(client);
            }else
            {
                //向该用户发送"已满"
                Thread.Sleep(500);  //暂停线程500ms
                tcpclient.Close();
            }
           
        }
    }

    //防止程序没有正确退出
    void OnApplicationQuit()
    {
        if (serverThread != null && serverThread.IsAlive)
        { 
            serverThread.Abort();
            //serverThread.Join();
            Debug.Log("serverThread :"+ serverThread.IsAlive);
        }
        if (listener != null)
        {
            listener.Stop();
        }
        //关闭所有用户的socket和线程
        foreach (ClientSocket user in _clients)
        {
            if (user != null) user.Close();
        }
    }
    void OnDestroy()
    {
        Debug.Log("server OnDestroy");
        OnApplicationQuit();
    }

    //Client接收发送类
    public class ClientSocket
    {
        //建立的通讯
        private TcpClient client;
        //stream流
        private NetworkStream stream;
        //socket是否处于活动中
        private volatile bool __connected = false;
        public bool connected { get { return __connected; } }


        //接受队列
        public Queue<string> recvQueue = new Queue<string>();
        //发送队列
        public Queue<string> sendQueue = new Queue<string>();
        //缓存区大小
        private int maxBufferSize = 4096;


        //线程
        public Thread clientThread = null;
        //是否停止线程
        private volatile bool stop = false;

        
        //构造函数
        public ClientSocket(TcpClient _client)
        {
            client = _client;
            stream = client.GetStream();

            //stop = false;
            //开启线程
            clientThread = new Thread(new ThreadStart(StartClient));
            clientThread.IsBackground = true;
            clientThread.Start();
        }

        //socket连接是否有效
        bool IsOpen()
        {
            return !((client.Client.Poll(1000, SelectMode.SelectRead) && (client.Client.Available == 0)) || !client.Client.Connected);
        }

        //Client线程
        void StartClient()
        {
            byte[] recvBuf = new byte[maxBufferSize];

            while (!stop)
            {
                //连接是否有效
                __connected = IsOpen();

                //检查发送队列
                if (sendQueue.Count > 0 && __connected)
                {
                    byte[] buffer = Encoding.UTF8.GetBytes(sendQueue.Dequeue());
                    stream.Write(buffer, 0, buffer.Length);
                    stream.Flush();
                }

                //检查流接受数据
                if (stream.DataAvailable && __connected)
                {
                    int bytesRead = stream.Read(recvBuf, 0, maxBufferSize);  //从流中获取数据,阻塞方法(如果没有数据,将阻塞线程)
                    if (bytesRead > 0)
                    {
                        string message = Encoding.UTF8.GetString(recvBuf);
                        Debug.Log("收到客户端消息:" + message);
                        recvQueue.Enqueue(message);
                    }
                }

                //线程暂停时间(毫秒)
                Thread.Sleep(10);  
            }
            //Close();
        }
        //添加消息到发送队列(外部方法)
        public void Send(string message)
        {
            sendQueue.Enqueue(message);
        }
        //获取一条消息(外部方法)
        public string Recv()
        {
            if (recvQueue.Count <= 0)
            {
                return null;
            }
            return recvQueue.Dequeue();
        }

        //关闭用户线程和socket连接
        public void Close()
        {
            stop = true;
            stream.Close();
            client.Close();
            if (clientThread != null && clientThread.IsAlive)
            {
                clientThread.Abort();
                // 如果没有正确关闭线程,这里的Join就会阻塞,就会卡死编辑器
                //sendThread.Join();
                Debug.Log("server-clientThread: " + clientThread.IsAlive);
            }

        }
    }
}




配置脚本:

public class NetworkValue {

    //连接地址
    private static string _ip = "192.168.1.100";
    //端口号
    private static int _port = 1234;



    public static string ip
    {
        get
        {
            return _ip;
        }

        set
        {
            _ip = value;
        }
    }

    public static int port
    {
        get
        {
            return _port;
        }

        set
        {
            _port = value;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值