37.Socket类UDP异步常用方法

37.网络通信-套接字Socket-UDP通信-异步-异步通信常用方法


37.1 知识点

Socket中UDP通信中的异步方法

  • 通过之前的学习,UDP用到的通信相关方法主要就是 SendToReceiveFrom
  • 所以在讲解UDP异步通信时也主要是围绕着收发消息相关方法来讲解
  • 主要也分Begin开头和Async结尾的方法 Begin开头的回调函数中同样要配合End开头的方法
// 创建一个新的Socket对象,采用UDP协议,IPv4地址族
Socket socketUdp = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// 将字符串转换为字节数组
byte[] bytes = Encoding.UTF8.GetBytes("123123lkdsajlfjas");
// 创建服务端端口号和IP
// 创建一个IP地址为127.0.0.1,端口号为8080的IPEndPoint实例对象
EndPoint ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);

UDP通信中Begin相关异步方法

Socket.BeginSendTo 向指定IP和端口异步发送数据

Socket.EndSendTo 结束异步发送操作

// BeginSendTo方法 开始向指定IP和端口发送数据,将结果异步传回SendToOver回调函数进行处理
// 参数依次为:要发送的数据字节数组、从字节数组的哪个位置开始发送、发送数据的长度、SocketFlags标识、目标IP和端口号、回调函数、回调函数的参数
socketUdp.BeginSendTo(bytes, 0, bytes.Length, SocketFlags.None, ipPoint, SendToOver, socketUdp);

// 发送数据完成时的回调函数
private void SendToOver(IAsyncResult asyncResult)
{
    try
    {
        // 从异步结果中获取Socket对象实例
        Socket socketUdp = asyncResult.AsyncState as Socket;

        // 结束异步发送操作
        socketUdp.EndSendTo(asyncResult);

        // 打印发送成功提示信息
        print("发送成功");
    }
    catch (SocketException s)
    {
        // 打印发送失败提示信息
        print("发送失败" + s.SocketErrorCode + s.Message);
    }
}

Socket.BeginReceiveFrom 异步从UDP客户端接收数据

Socket.EndReceiveFrom 结束异步接收操作,并返回接收到的字节数

// BeginReceiveFrom方法 开始异步从UDP客户端接收数据,将接收到的数据放入缓存区cacheBytes中
// 接收数据的来源ip和端口号会被保存在ipPoint变量中 这里没有新建 复用了之前服务端的
// 当有数据到达时就会自动调用ReceiveFromOver回调函数进行处理
// 参数依次为:缓存区、缓存区的起始位置、最大接收数据长度、SocketFlags标识、接收数据的来源IPEndPoint、回调函数、回调函数的参数
socketUdp.BeginReceiveFrom(cacheBytes, 0, cacheBytes.Length, SocketFlags.None, ref ipPoint, ReceiveFromOver, (socketUdp, ipPoint));

// 接收数据完成时的回调函数
private void ReceiveFromOver(IAsyncResult asyncResult)
{
    try
    {
        // 从异步结果中获取Socket对象实例和远程IPEndPoint实例
        // 因为BeginReceiveFrom回调函数的参数填了(socketUdp, ipPoint) 所以可直接用元组
        (Socket socketUdp, EndPoint ipPoint) socketUdpAndIpPoint = ((Socket, EndPoint))asyncResult.AsyncState;

        // 结束异步接收操作,并返回接收到的字节数
        int num = socketUdpAndIpPoint.socketUdp.EndReceiveFrom(asyncResult, ref socketUdpAndIpPoint.ipPoint);

        // 处理接收到的数据

        // 再次开始异步接收数据,以便下一次有数据到达时能够自动调用该回调函数处理
        socketUdpAndIpPoint.socketUdp.BeginReceiveFrom(cacheBytes, 0, cacheBytes.Length, SocketFlags.None, ref socketUdpAndIpPoint.ipPoint, ReceiveFromOver, socketUdpAndIpPoint);
    }
    catch (SocketException s)
    {
        // 打印接收失败提示信息
        print("接受消息出问题" + s.SocketErrorCode + s.Message);
    }
}

UDP通信中Async相关异步方法

Socket.SendToAsync 开始向指定IP和端口发送数据

// SendToAsync方法 开始向指定IP和端口发送数据 发送完成后在SendToAsync回调函数处理
SocketAsyncEventArgs socketAsyncEventArgs1 = new SocketAsyncEventArgs();
// 设置要发送的数据
socketAsyncEventArgs1.SetBuffer(bytes, 0, bytes.Length);
// 设置服务端IP地址
socketAsyncEventArgs1.RemoteEndPoint = ipPoint;
// 附加完成事件处理程序 这里添加自定义完成回调 只是函数名一样
socketAsyncEventArgs1.Completed += SendToAsync;
// 启动发送操作
socketUdp.SendToAsync(socketAsyncEventArgs1);



//发送完成回调
private void SendToAsync(object socket, SocketAsyncEventArgs socketAsyncEventArgs1)
{
    // 检查发送操作是否成功
    if (socketAsyncEventArgs1.SocketError == SocketError.Success)
    {
        // 发送操作成功
        print("发送成功");
    }
    else
    {
        // 发送操作失败
        print("发送失败");
    }
}

Socket.ReceiveFromAsync 开始向指定IP和端口发送数据

// ReceiveFromAsync 开始异步从UDP客户端接收数据 接收完成后在ReceiveFromAsync回调函数进行处理
SocketAsyncEventArgs socketAsyncEventArgs2 = new SocketAsyncEventArgs();
// 设置接收数据的缓冲区 传入字节数组作为容器
socketAsyncEventArgs2.SetBuffer(cacheBytes, 0, cacheBytes.Length);
// 声明用于接收服务端的IP地址
socketAsyncEventArgs2.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
// 附加完成事件处理程序 这里添加自定义完成回调 只是函数名一样
socketAsyncEventArgs2.Completed += ReceiveFromAsync;
// 启动接收操作
socketUdp.ReceiveFromAsync(socketAsyncEventArgs2);


//接收完成回调
private void ReceiveFromAsync(object socket, SocketAsyncEventArgs socketAsyncEventArgs2)
{
    // 检查接收操作是否成功
    if (socketAsyncEventArgs2.SocketError == SocketError.Success)
    {
        // 接收操作成功
        print("接收成功");

        // 您可以通过 BytesTransferred 访问接收的字节数
        // int receivedBytes = socketAsyncEventArgs2.BytesTransferred;

        // 您可以从以下缓冲区中访问接收的数据:
        // byte[] receivedData = socketAsyncEventArgs2.Buffer;

        //也可以直接通过cacheBytes

        Socket socketUdp = socket as Socket;

        // 设置接收数据的缓冲区,指定从哪里开始接收和要接收多少数据 因为外面已经传了cacheBytes 可以不用再传一次
        socketAsyncEventArgs2.SetBuffer(0, cacheBytes.Length);

        // 启动另一个接收操作
        socketUdp.ReceiveFromAsync(socketAsyncEventArgs2);
    }
    else
    {
        // 接收操作失败
        print("接收失败");
    }
}

总结

由于学习了TCP相关的知识点,所以UDP的相关内容的学习就变得简单了。他们异步通信的唯一的区别就是API不同,使用规则都是一致的。


37.2 知识点代码

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

public class Lesson37_网络通信_套接字Socket_UDP通信_异步_异步通信常用方法 : MonoBehaviour
{
    private byte[] cacheBytes = new byte[512];

    void Start()
    {
        #region 知识点一 Socket中UDP通信中的异步方法

        //通过之前的学习,UDP用到的通信相关方法主要就是
        //SendTo和ReceiveFrom
        //所以在讲解UDP异步通信时也主要是围绕着收发消息相关方法来讲解
        //主要也分Begin开头和Async结尾的方法 Begin开头的回调函数中同样要配合End开头的方法

        // 创建一个新的Socket对象,采用UDP协议,IPv4地址族
        Socket socketUdp = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        // 将字符串转换为字节数组
        byte[] bytes = Encoding.UTF8.GetBytes("123123lkdsajlfjas");
        // 创建服务端端口号和IP
        // 创建一个IP地址为127.0.0.1,端口号为8080的IPEndPoint实例对象
        EndPoint ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);

        #endregion

        #region 知识点二 UDP通信中Begin相关异步方法

        // BeginSendTo方法 开始向指定IP和端口发送数据,将结果异步传回SendToOver回调函数进行处理
        // 参数依次为:要发送的数据字节数组、从字节数组的哪个位置开始发送、发送数据的长度、SocketFlags标识、目标IP和端口号、回调函数、回调函数的参数
        socketUdp.BeginSendTo(bytes, 0, bytes.Length, SocketFlags.None, ipPoint, SendToOver, socketUdp);

        // BeginReceiveFrom方法 开始异步从UDP客户端接收数据,将接收到的数据放入缓存区cacheBytes中
        // 接收数据的来源ip和端口号会被保存在ipPoint变量中 这里没有新建 复用了之前服务端的
        // 当有数据到达时就会自动调用ReceiveFromOver回调函数进行处理
        // 参数依次为:缓存区、缓存区的起始位置、最大接收数据长度、SocketFlags标识、接收数据的来源IPEndPoint、回调函数、回调函数的参数
        socketUdp.BeginReceiveFrom(cacheBytes, 0, cacheBytes.Length, SocketFlags.None, ref ipPoint, ReceiveFromOver, (socketUdp, ipPoint));

        #endregion

        #region 知识点三 UDP通信中Async相关异步方法

        // SendToAsync方法 开始向指定IP和端口发送数据 发送完成后在SendToAsync回调函数处理
        SocketAsyncEventArgs socketAsyncEventArgs1 = new SocketAsyncEventArgs();
        // 设置要发送的数据
        socketAsyncEventArgs1.SetBuffer(bytes, 0, bytes.Length);
        // 设置服务端IP地址
        socketAsyncEventArgs1.RemoteEndPoint = ipPoint;
        // 附加完成事件处理程序
        socketAsyncEventArgs1.Completed += SendToAsync;
        // 启动发送操作
        socketUdp.SendToAsync(socketAsyncEventArgs1);

        // ReceiveFromAsync 开始异步从UDP客户端接收数据 接收完成后在ReceiveFromAsync回调函数进行处理
        SocketAsyncEventArgs socketAsyncEventArgs2 = new SocketAsyncEventArgs();
        // 设置接收数据的缓冲区 传入字节数组作为容器
        socketAsyncEventArgs2.SetBuffer(cacheBytes, 0, cacheBytes.Length);
        // 声明用于接收服务端的IP地址
        socketAsyncEventArgs2.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
        // 附加完成事件处理程序
        socketAsyncEventArgs2.Completed += ReceiveFromAsync;
        // 启动接收操作
        socketUdp.ReceiveFromAsync(socketAsyncEventArgs2);

        #endregion

        #region 总结

        //由于学习了TCP相关的知识点
        //所以UDP的相关内容的学习就变得简单了
        //他们异步通信的唯一的区别就是API不同,使用规则都是一致的

        #endregion
    }

    #region 知识点二 UDP通信中Begin相关异步方法

    // 发送数据完成时的回调函数
    private void SendToOver(IAsyncResult asyncResult)
    {
        try
        {
            // 从异步结果中获取Socket对象实例
            Socket socketUdp = asyncResult.AsyncState as Socket;

            // 结束异步发送操作
            socketUdp.EndSendTo(asyncResult);

            // 打印发送成功提示信息
            print("发送成功");
        }
        catch (SocketException s)
        {
            // 打印发送失败提示信息
            print("发送失败" + s.SocketErrorCode + s.Message);
        }
    }

    // 接收数据完成时的回调函数
    private void ReceiveFromOver(IAsyncResult asyncResult)
    {
        try
        {
            // 从异步结果中获取Socket对象实例和远程IPEndPoint实例
            (Socket socketUdp, EndPoint ipPoint) socketUdpAndIpPoint = ((Socket, EndPoint))asyncResult.AsyncState;

            // 结束异步接收操作,并返回接收到的字节数
            int num = socketUdpAndIpPoint.socketUdp.EndReceiveFrom(asyncResult, ref socketUdpAndIpPoint.ipPoint);

            // 处理接收到的数据

            // 再次开始异步接收数据,以便下一次有数据到达时能够自动调用该回调函数处理
            socketUdpAndIpPoint.socketUdp.BeginReceiveFrom(cacheBytes, 0, cacheBytes.Length, SocketFlags.None, ref socketUdpAndIpPoint.ipPoint, ReceiveFromOver, socketUdpAndIpPoint);
        }
        catch (SocketException s)
        {
            // 打印接收失败提示信息
            print("接受消息出问题" + s.SocketErrorCode + s.Message);
        }
    }

    #endregion

    #region 知识点三 UDP通信中Async相关异步方法

    //发送完成回调
    private void SendToAsync(object socket, SocketAsyncEventArgs socketAsyncEventArgs1)
    {
        // 检查发送操作是否成功
        if (socketAsyncEventArgs1.SocketError == SocketError.Success)
        {
            // 发送操作成功
            print("发送成功");
        }
        else
        {
            // 发送操作失败
            print("发送失败");
        }
    }

    //接收完成回调
    private void ReceiveFromAsync(object socket, SocketAsyncEventArgs socketAsyncEventArgs2)
    {
        // 检查接收操作是否成功
        if (socketAsyncEventArgs2.SocketError == SocketError.Success)
        {
            // 接收操作成功
            print("接收成功");

            // 您可以通过 BytesTransferred 访问接收的字节数
            // int receivedBytes = socketAsyncEventArgs2.BytesTransferred;

            // 您可以从以下缓冲区中访问接收的数据:
            // byte[] receivedData = socketAsyncEventArgs2.Buffer;

            //也可以直接通过cacheBytes

            Socket socketUdp = socket as Socket;

            // 设置接收数据的缓冲区,指定从哪里开始接收和要接收多少数据 因为外面已经传了cacheBytes 可以不用再传一次
            socketAsyncEventArgs2.SetBuffer(0, cacheBytes.Length);

            // 启动另一个接收操作
            socketUdp.ReceiveFromAsync(socketAsyncEventArgs2);
        }
        else
        {
            // 接收操作失败
            print("接收失败");
        }
    }

    #endregion
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏