Socket之Unity客户端

82 阅读3分钟

一、逻辑思路

创建套接字Socket 用于连接服务端 和判断是否连接客户端的开关

Socket socket;
private bool isConnected = false;  //是否连接到服务器的开关 因为后面关闭服务的时候会变成True

2、首先创建两个队列去临时存储接收和发送的消息

 //创建一个队列 用来存储要发送的消息
 public Queue<string> sendMsgQueue = new Queue<string>();
 //创建一个队列  用来存储要接收的消息
 public Queue<string> receiveQueue = new Queue<string>();

3、再创建接收消息的字节数组

//接收消息的容器  以及用来存取字节长度的临时变量receiveNum
byte[] receiveBytes = new byte[1024*1024];
int receiveNum;

连接服务器的方法功能模块Connect(string host,int port) 传入服务端的IP和端口号

判断是否连接 if (isConnected) return;  如果没有连接 就跳出连接
设置Socket的连接方式 流程和服务端的差不多
//设置连接方式
socket=new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//获取服务器的 IPEndPoint
IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse(host), port); //里面输入服务器的IP和端口号
使用Try{}Catch(){} 去捕捉可能出现的问题
Try中  放的是连接成功的代码逻辑  
//进行与服务端的连接  
socket.Connect(ipPoint); 
//后面使用异步 去实现收发信息
ThreadPool.QueueUserWorkItem(SendMsg);
ThreadPool.QueueUserWorkItem(receiveMsg);

异步发送消息的方法 需要循环判断是否发送消息 所以要用到While

SendMsg(object obj)  //object是使用QueueUserWorkItem 必须要有的
使用While(!isConnected)去控制收发消息 去判断队列是否不为空sendMsgQueue.Count > 0
如果不为空的话 就取出队列的首个元素进行发送到客户端 socket.Send(Encoding.UTF8.GetBytes(sendMsgQueue.Dequeue()));
其中,存在一个问题,怎么把信息存到队列中去呢?
再创建一个外部方法Send(string info)  进行将需要发送的消息存放队列中去
方法体内部只要将info存放到队列中 sendMsgQueue.Enqueue(info);
SendMsg不停地循环判断队列是否为空,不为空就取出,进行发送消息 实现了客户端发送消息的逻辑。

异步接收消息的方法 需要循环判断是否收到消息 所以要用到While

receiveMsg(object obj)  //ThreadPool.QueueUserWorkItem(receiveMsg);上面线程池调用
 使用While(!isConnected)去控制接收消息 
 判断是否收到消息if (socket.Available > 0)
 收到的话//获取长度
receiveNum = socket.Receive(receiveBytes);
//解析
receiveQueue.Enqueue(Encoding.UTF8.GetString(receiveBytes,0,receiveNum));
存到队列了之后 怎么才能打印出来呢?
放到Update中进行判断队列是否大于0大于0的话就取出元素
 if (receiveQueue.Count > 0)
 {
     print(receiveQueue.Dequeue());
 }

关闭方法

public void Close()
{
    if(socket != null)
    {
        socket.Shutdown(SocketShutdown.Both);
        socket.Close();

        //关闭接收和发送服务
        isConnected = false;
    }
}
private void OnDestroy()
{
    Close();
}

代码

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

public class NetMgr : MonoBehaviour
{
    //单例模式
    public static NetMgr instance;
    public static NetMgr Instance=>instance;

    private bool isConnected = false;  //是否连接到服务器的开关

    //创建一个队列 用来存储要发送的消息
    public Queue<string> sendMsgQueue = new Queue<string>();
    //创建一个队列  用来存储要接收的消息
    public Queue<string> receiveQueue = new Queue<string>();


    //接收消息的容器
    byte[] receiveBytes = new byte[1024*1024];
     int receiveNum;

    Socket socket;


    

    private void Awake()
    {
        instance = this;
    }

  

    private void Update()
    {
        if (receiveQueue.Count > 0)
        {
            print(receiveQueue.Dequeue());
        }
    }

    //连接服务器  传入IP和端口号
    public void Connect(string host, int port)
    {
        //1.判断是否是连接状态  如果是 就返回
        if (isConnected)
            return;
        //设置连接方式
        socket=new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //获取服务器的 IPEndPoint
        IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse(host), port); //里面输入服务器的IP和端口号
        try
        {
            socket.Connect(ipPoint);  //连接 成功
            Send("连接成功");
            //进行收发消息  
            //用线程池进行嗲用
            ThreadPool.QueueUserWorkItem(SendMsg);
            ThreadPool.QueueUserWorkItem(receiveMsg);

        }
        catch(SocketException e)
        {
            if (e.ErrorCode == 10061)
            {
                print("服务器拒绝连接");
            }
            else
            {
                print("连接服务器失败" + e.ErrorCode);
            }
            return;
        }
        
        
    }

    /// <summary>
    /// 发送消息 外部
    /// </summary>
    /// <param name="info"></param>
    public void Send(string info)
    {
        sendMsgQueue.Enqueue(info);
    }

    public void SendMsg(object obj)
    {
        while (!isConnected)
        {
            if(sendMsgQueue.Count > 0)
            {
                
                socket.Send(Encoding.UTF8.GetBytes(sendMsgQueue.Dequeue()));
            }
        }
    }

    /// <summary>
    /// 不停的接收消息
    /// </summary>
    private void receiveMsg(object obj)
    {
        while (!isConnected)
        {
            if (socket.Available > 0)
            {
                //获取长度
                receiveNum = socket.Receive(receiveBytes);
                //解析
                receiveQueue.Enqueue(Encoding.UTF8.GetString(receiveBytes,0,receiveNum));
            }
        }
    }

    public void Close()
    {
        if(socket != null)
        {
            socket.Shutdown(SocketShutdown.Both);
            socket.Close();

            //关闭接收和发送服务
            isConnected = false;
        }
    }
    private void OnDestroy()
    {
        Close();
    }
}