Unity/C# Socket框架学习遇到的相关方法

 最近在尝试unity的Socket建立,直接白嫖的代码同时来自己学习。可以先去看一下这个up讲解的视频是否满足自己需求。

Unity一个脚本解决UDP双端通讯_哔哩哔哩_bilibili

下面是代码:(我把其分成几部分来细说,有错误的地方还请指出!感谢大家~)

第一部分:头文件函数等

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

此部分不做介绍。

第二部分:建立客户端通信插口

    //定义客户端通信插口
    Socket socket_c;
    [Header("---------------------客户端--------------------")]
    public string biji = "备注";
    [Header("存放对方的接收ip")]
    public string oppositeIP = "192.168.2.2";
    [Header("存放对方的接收端口")]
    public int oppositePort = 8888;
    //对方服务端ip端口对
    IPEndPoint oppositeIpEnd;
    //广播的所有ip
    List<string> allIPv4 = new List<string>();

这一部分主要建立两个变量分别存储对方ip地址和端口号。

其中IPEndPoint类,是将 IP 地址和服务端口号组合在一起。

第三部分:建立服务端通信插口

    //定义服务端通信插口
    Socket socket_s;
    [Header("---------------------服务端--------------------")]
    [Header("本机开放的端口")]
    public int selfConnectPoint = 7777;
    // [Header("本机ip自动获取")]
    public static string selfAddress = "";
    //本机服务端所监听的ip端口对
    EndPoint selfListenEnd;
    //监听线程
    Thread connectThread;

第三部分是当unity作为服务端时,需要暴露出一个端口和ip地址,同时开启了一个监听线程。

这里的ip地址后期会自动获取,详见下面

第四部分:字符串接受面板显示

    [Header("------------------入站的字符串---------------")]
    public string recvStr;
     //定义接受byte数组的长度
    int recvLen = 0;
    //接收到的byte数据
    byte[] recvData = new byte[1024];
    //要发送的的byte数据
    byte[] sendData = new byte[1024];

第四部分,这里会在unity的spector面板显示传入的字符串,还有接受和发送的相关数组。

第五部分:Unity脚本初始化函数

   void Start()
    {

        //去除ip 前后空格
        oppositeIP = oppositeIP.Trim(); //去掉字符串的前后空格
        //定义本机服务器的ip和端口对
        if (selfAddress == "")
        {
            selfAddress = GetLocalIP();
        }
        selfAddress = selfAddress.Trim();
        GetBroadcastIP(selfAddress);
        //初始化
        InitSocket();
    }

第五部分,在这里分别对unity做客户端和服务端初始化。首先将对方的ip格式进行整理,即oppsoiteIP.Trim()。同时通过GetLocalIP()自定义函数获得本机的IP地址,将本机地址发送给广播函数,后期要以本机地址为基础向192.168.56.1到192.168.56.255发送广播数据报。

在这里同时进行socket()初始化。

第六部分:Socket()初始化

    void InitSocket()
    {
        //作为客户端
        //定义对方的ip和端口对
        oppositeIpEnd = new IPEndPoint(IPAddress.Parse(oppositeIP), oppositePort);
        socket_c = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        //socketListen.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);//设置SOCKET允许多个SOCKET访问同一个本地IP地址和端口号 

        //作为服务端    
        //本机服务器监听的ip端口对
        selfListenEnd = new IPEndPoint(IPAddress.Parse(selfAddress), selfConnectPoint);
        socket_s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        socket_s.Bind(selfListenEnd);
        //开启本机服务器监听线程
        connectThread = new Thread(new ThreadStart(SocketReceive));
        connectThread.Start();


        //给目标服务端发送数据测试  
        SocketSendDefault(selfListenEnd.ToString() + ":first");
        print("对方接到表示连接成功");
    }

第六部分为socket的初始化:

对于客户端来说,将客户端的IP地址和端口统一并赋给oppositeEnd,建立一个客户端的socket_c。

对于服务端来说,将服务端的IP地址和端口统一并赋给selfListenEnd,建立一个服务端的socket_s,将此socket_s与selfListenEnd绑定。

开启一个监听线程,并传入参数SocketReceive.(下面会说)

通过SocketSendDefault()测试是否连接成功。

第七部分:服务器的监听

    //本机服务器监听
    void SocketReceive()
    {
        while (true)
        {
            recvData = new byte[1024];
            recvLen = socket_s.ReceiveFrom(recvData, ref selfListenEnd);
            recvStr = Encoding.UTF8.GetString(recvData, 0, recvLen);
            Debug.Log("信息来自" + selfListenEnd.ToString() + ":" + recvStr);
            getNew = true;
        }
    }

第七部分为服务器的监听

socket_s.ReceiveFrom()为接收数据并存储其数据来源客户端,并最终返回数组长度。

 Encoding.UTF8.GetString将字符串用UTF8方法编码。

Debug.Log为Unity的控制台打印内容。

第八部分:作为客户端发送

//默认ip端口发送
    public void SocketSendDefault(string sendStr)
    {
        //清空
        sendData = new byte[1024];
        //数据转换
        sendData = Encoding.UTF8.GetBytes(sendStr);
        //发送给指定服务端
        socket_c.SendTo(sendData, sendData.Length, SocketFlags.None, oppositeIpEnd);
    }

    //自定义ip端口发送
    public void SocketSendCustom(string sendStr, string ip, int port)
    {
        //清空
        sendData = new byte[1024];
        //数据转换
        sendData = Encoding.UTF8.GetBytes(sendStr);
        IPEndPoint aimIpEnd;

        aimIpEnd = new IPEndPoint(IPAddress.Parse(ip), port);
        //发送给指定服务端
        socket_c.SendTo(sendData, sendData.Length, SocketFlags.None, aimIpEnd);

    }

    //默认ip端口群发
    public void SendToAllDefault(string sendMsg)
    {
        StartCoroutine(SocketBroadcastSend(sendMsg, oppositePort));


    }

    //自定义ip端口群发
    public void SendToAllCustom(string sendMsg, int port)
    {
        StartCoroutine(SocketBroadcastSend(sendMsg, port));

    }
    IEnumerator SocketBroadcastSend(string sendStr, int port)
    {
        //清空
        byte[] sendData_thread = new byte[1024];
        //数据转换
        sendData_thread = Encoding.UTF8.GetBytes(sendStr);
        IPEndPoint aimIpEnd;

        foreach (string ip in allIPv4)
        {
            Debug.Log(ip);
            aimIpEnd = new IPEndPoint(IPAddress.Parse(ip), port);

            socket_c.SendTo(sendData_thread, sendData_thread.Length, SocketFlags.None, aimIpEnd);
        }
        yield return null;
    }

第九部分:线程的关闭

    //连接关闭
    void SocketQuit()
    {
        //关闭线程
        if (connectThread != null)
        {
            connectThread.Interrupt();
            connectThread.Abort();
        }
        //最后关闭socket
        if (socket_c != null)
            socket_c.Close();
        if (socket_s != null)
            socket_s.Close();

        StopAllCoroutines();


    }
    void OnApplicationQuit()
    {
        SocketQuit();
    }

第十部分:Unity更新

    void Update()
    {
        if (getNew == true)
        {
            getNew = false;
            //执行接收文本事件
        }
    }

第十一部分:自动获取本机地址

public static string GetLocalIP()
    {
        try
        {
            string HostName = Dns.GetHostName();             //得到主机名

            //返回一个IPHostEntry实例,其中包含有关 HostName 中指定的主机的地址信息
            // IPHostEntry为 Internet 主机地址信息提供容器类
            //方法 GetHostEntry 在 DNS 服务器中查询与主机名或 IP 地址关联的 IP 地址,并将 IP 地址解析为 IPHostEntry 实例。
            IPHostEntry IpEntry = Dns.GetHostEntry(HostName);
            
            for (int i = 0; i < IpEntry.AddressList.Length; i++)
            {
                //从IP地址列表中筛选出IPv4类型的IP地址
                //AddressFamily.InterNetwork表示此IP为IPv4,
                //AddressFamily.InterNetworkV6表示此地址为IPv6类型
                if (IpEntry.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
                {
                    Debug.Log(IpEntry.AddressList[i].ToString());
                    return IpEntry.AddressList[i].ToString();
                }
            }
            return "noIp";
        }
        catch
        {
            Debug.Log("ipGetFailed");
            return ("ipGetFailed");
        }

    }

第十二部分:广播机制

    public void GetBroadcastIP(string ip)
    {
        string[] nums = ip.Split('.');
        string head = nums[0] + "." + nums[1] + "." + nums[2] + ".";
        for (int i = 1; i < 255; i++)
        {

            allIPv4.Add(head + i.ToString());
        }


    }

ps源码见b站链接

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值