Socket的UDP实例

一般来说,在Socket传输的实际应用中使用TCP较多,这里的UDP只是简单的实现了两个用户之间的通信
1、首先,我们需要清楚什么是UDP:

UDP —用户数据报协议,是一个无连接的简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。

UDP是一种面向无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。

2、UDP的特点:

UDP是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息,由于通讯不需要连接,所以可以实现广播发送。 UDP传输数据时有大小限制,每个被传输的数据报必须限定在64KB之内。 UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。

3、UDP的适用情况:

UDP是面向消息的协议,通信时不需要建立连接,数据的传输自然是不可靠的,UDP一般用于多点通信和实时的数据业务,比如:

  • 语音广播
  • 视频
  • QQ
  • TFTP(简单文件传送)
  • SNMP(简单网络管理协议)
  • RIP(路由信息协议,如报告股票市场,航空信息)
  • DNS(域名解释)

注重速度流畅

UDP操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的分散系统中client/server应用程序。例如视频会议系统,并不要求音频视频数据绝对的正确,只要保证连贯性就可以了,这种情况下显然使用UDP会更合理一些。

4、UDP传输代码:
流程: 1、初始化Socket环境 --> 2、创建客户端Socket --> 3、Send和Receive消息 --> 4、关闭Socket
using System.Collections.Generic;
using UnityEngine;
using System.Net.Sockets;
using System.Net;
using System.Threading;

public class UDPSocket
{
	//委托
    public delegate void ReceiveDelegate(byte[] buffer, int realSize, string ip, int port);
    //代理
    ReceiveDelegate receiveCallBack;

    public Socket myUDP;
    /// <summary>
    /// 传递一个端口号
    /// </summary>
    /// <param name="point"></param>
    public UDPSocket(int point, int bufferSize, ReceiveDelegate back)
    {
        receiveCallBack = back;
        Initial(point, bufferSize);
    }

    /// <summary>
    /// 初始化Socket(套接字 描述符)
    /// </summary>
    /// <param name="point"></param>
    public void Initial(int point, int size)
    {
        receiveBuffer = new byte[size];
        //AddressFamily: 地址协议族:ip4  ip6
        //ProtocolType:UDP  TCP                    
        //SocketType:TCP :数据流方式Stream   UDP:数据报Dgram
        myUDP = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

        //显卡的地址
        //绑定网卡:IPAddress.Any:自动获取一个比较闲的网卡
        //端口号:不是1024都可以
        IPEndPoint tmpIPPoint = new IPEndPoint(IPAddress.Any, point);
        //绑定IP地址和端口号
        myUDP.Bind(tmpIPPoint);

        Thread tmpThread = new Thread(ReceiveThread);
        tmpThread.Start();
    }

    bool isRun = true;
    public void ReceiveThread()
    {
        while (isRun)
        {
            if (myUDP != null && myUDP.Available < 1)
            {
                Thread.Sleep(100);
            }
            ReceiveBytes();
        }
    }

    /// <summary>
    /// 发送消息
    /// </summary>
    /// <param name="buffer">发送的byte[]</param>
    /// <param name="ip">IP地址</param>
    /// <param name="port">端口号</param>
    /// Send:发送TDP
    /// SendTo:发送UDP
    public void SendBytes(byte[] buffer, string ip, int port)
    {
        IPEndPoint tmpEnd = new IPEndPoint(IPAddress.Parse(ip), port);
        int realSend = myUDP.SendTo(buffer, buffer.Length, SocketFlags.None, tmpEnd);
    }

    byte[] receiveBuffer;
    //存接收方的IP地址、端口号
    IPEndPoint receivePoint = new IPEndPoint(IPAddress.Any, 0);

    /// <summary>
    /// 接收消息
    /// </summary>
    /// ReceiveFrom:SnedTo
    /// Receive:Send
    public void ReceiveBytes()
    {
        EndPoint tpEnd = receivePoint;

        //ref:会修改IP地址和端口号
        //真正接收的字节数           阻塞
        int realReceive = myUDP.ReceiveFrom(receiveBuffer, ref tpEnd);
        receiveCallBack(receiveBuffer, realReceive, receivePoint.Address.ToString(), receivePoint.Port);
    }

    /// <summary>
    /// 关闭(释放)
    /// </summary>
    public void Dispose()
    {
        isRun = false;

        if (myUDP != null)
        {
            myUDP.Close();
        }
    }
}

调用UDPSocket实现不同端口的信息传递

using System;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

public class UDPQQTalk : MonoBehaviour
{
    [SerializeField] private InputField mine;
    [SerializeField] private Transform parent;
    [SerializeField] private GameObject prefab;
    [SerializeField] private ScrollRect scroll;
    [SerializeField] private RectTransform viewPort;

    [Header("发送的端口")]
    [SerializeField] private int sendPort;
    [Header("接收的端口")]
    [SerializeField] private int receivePort;

    private UDPSocket sendSocket;
    private byte[] reBuffer;
    private bool isReceive;

    void SendBuffer(byte[] buffer, int realSize, string ip, int port)
    {
        lock (this)
        {
            reBuffer = new byte[realSize];
            Buffer.BlockCopy(buffer, 0, reBuffer, 0, realSize);

            isReceive = true;
        }
    }

    private void Start()
    {
        sendSocket = new UDPSocket(sendPort, 1024, new UDPSocket.ReceiveDelegate(SendBuffer));
        mine.onEndEdit.AddListener(_ => MineTalk());
    }

    private void Update()
    {
        if (isReceive)
        {
            isReceive = false;
            lock (this)
            {
                Debug.Log("接收消息:" + sendPort);
                //进行UI的操作
                Text text = Instantiate(prefab, parent).GetComponent<Text>();
                string tp = Encoding.Default.GetString(reBuffer);
                text.text = receivePort.ToString() + ":\n" + tp;
                Invoke("DoMove", 0.1f);
            }
        }
    }
    
    /// <summary>
    /// 发送方
    /// </summary>
    public void MineTalk()
    {
        if (!string.IsNullOrEmpty(mine.text))
        {
        	//UI操作
            Text text = Instantiate(prefab, parent).GetComponent<Text>();
            text.text = sendPort.ToString() + ":\n" + mine.text;
			//发送消息给接收端口
            byte[] buffer = Encoding.Default.GetBytes(mine.text);
            sendSocket.SendBytes(buffer, "127.0.0.1", receivePort);

            mine.text = string.Empty;
            Invoke("DoMove", 0.1f);
        }
    }

    /// <summary>
    /// 移动Content到最高处
    /// </summary>
    private void DoMove()
    {
        if (parent.GetComponent<RectTransform>().rect.height > viewPort.rect.height)
        {
            float height = parent.GetComponent<RectTransform>().rect.height - viewPort.rect.height;
            parent.DOLocalMoveY(height, 0.3f);
        }
    }
}
效果呈现:

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值