UN2L12——UDP异步通信常用方法
UN2L12——UDP异步通信常用方法
本章代码关键字
1 | socket.BeginSendTo() //异步发送消息,传入字节数组,偏移量,最大发送字节数,标识,目标IP与端口,回调函数和回调函数的参数 |
Socket的UDP通信中的异步方法
通过之前的学习,UDP用到的通信相关方法主要就是SendTo
和ReceiveFrom
所以在讲解UDP异步通信时,也主要是围绕着收发消息相关方法来讲解
由于学习了TCP相关的知识点,所以UDP的相关内容的学习就变得简单了
他们异步通信的唯一的区别就是API不同,使用规则都是一致的
-
Begin
开头的APIUDP通信的异步方法使用方式上和TCP通信异步方法大同小异,可参考:TCP_Begin开头的API
-
UDP发送消息
Begin
开头异步方法UDP开始异步发送消息使用
socket.BeginSendTo()
- 参数一:要发送的字节数组
- 参数二:偏移量,从字节数组的第几位开始发送,将一个消息分开发送时可以使用
- 参数三:发送消息字节数组最多发送出去多少字节,将一个消息分开发送时可以使用
- 参数四:
SocketFlag
枚举,也就是标识,一般传入空标识SocketFlag.None
即可 - 参数五:要发送消息到哪个IP地址和端口号
- 参数六:回调函数,参数为
IAsyncResult
- 参数七:传入到回调函数内的参数,一般传入
socket
自己,在回调函数内通过iAsyncResult.AsyncState
获取
在发送了消息后,会执行参数五的回调函数,并将参数六传入进去,可通过
iAsyncResult.AsyncState
获取
通过socket.EndSendTo()
可以获取发送出去了多少字节,需要传入回调函数的参数
一般不需要获取发送出去了多少字节,除非要将一个消息分批发送1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21void Start()
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
byte[] bytes = Encoding.UTF8.GetBytes("123123123123123");
EndPoint ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);
socket.BeginSendTo(bytes, 0, bytes.Length, SocketFlags.None, ipPoint, SendToOver, socket);
}
private void SendToOver(IAsyncResult result)
{
try
{
Socket s = result.AsyncState as Socket;
s.EndSendTo(result);
print("发送成功");
}
catch (SocketException e)
{
print("发送失败:" + e.SocketErrorCode + e.Message);
}
} -
UDP接收消息
Begin
开头异步方法开始异步接收消息使用
socket.BeginReceiveFrom()
- 参数一:用于接收消息的字节数组
- 参数二:偏移量,相当于从接收消息字节数组的第几位开始接收,处理分包、黏包可以就利用该参数
- 参数三:接收消息字节数组还能接收多少字节
- 参数四:
SocketFlag
枚举,也就是标识,一般传入空标识SocketFlag.None
即可 - 参数五:用来记录发送者IP地址和端口号的
EndPoint
- 参数六:回调函数,参数为
IAsyncResult
- 参数七:传入到回调函数内的参数,一般传入记录发送者的
EndPoint
和socket
自己,在回调函数内通过iAsyncResult.AsyncState
获取
在接收到消息后,会执行参数五的回调函数,并将参数六传入进去,可通过
iAsyncResult.AsyncState
获取
需要通过socket.EndReceiveFrom()
获取接收到了多少字节,需要传入回调函数的参数,
在回调函数内就可以处理消息,执行socket.BeginReceiveFrom()
开始下一次消息监听同样的,因为
socket.BeginReceiveFrom()
是异步方法,回调方法会继续执行,所以不构成递归,不需要担心爆栈(前提是正常运行)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26private byte[] cacheBytes = new byte[512];
void Start()
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
EndPoint ipPoint = new IPEndPoint(IPAddress.Any, 0);
socket.BeginReceiveFrom(cacheBytes, 0, cacheBytes.Length, SocketFlags.None, ref ipPoint, ReceiveToOver, (socket, ipPoint));
}
private void ReceiveToOver(IAsyncResult result)
{
try
{
(Socket s, EndPoint ipPoint) info = ((Socket, EndPoint))result.AsyncState;
//返回值 就是接收了多少个字节数
int num = info.s.EndReceiveFrom(result, ref info.ipPoint);
//处理消息
print(Encoding.UTF8.GetString(cacheBytes, 0, num));
//处理完消息,又继续接收消息
info.s.BeginReceiveFrom(cacheBytes, 0, cacheBytes.Length, SocketFlags.None, ref info.ipPoint, ReceiveToOver, info);
}
catch (SocketException e)
{
print("接收消息失败:" + e.SocketErrorCode + e.Message);
}
}
-
-
Async
结尾的APIUDP通信的异步方法使用方式上和TCP通信异步方法大同小异,可参考:TCP_Async结尾的API
-
UDP发送消息
Async
结尾异步方法首先实例化一个
SocketAsyncEventArgs
,然后设置完成异步方法后执行的回调函数
回调函数有两个参数,一个是执行异步方法的Socket
(object
类型),一个是传入到异步方法的SocketAsyncEventArgs
然后,需要通过socketAsyncEventArgs.SetBuffer()
来设置要发送出去的字节数组
通过socketAsyncEventArgs.RemoteEndPoint
来设置要发送到哪个IP地址和端口号在回调函数中,需要通过
socketAsyncEventArgs.SocketError
来判断消息发送是否成功1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24void Start()
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
byte[] bytes = Encoding.UTF8.GetBytes("123123123123123");
EndPoint ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);
SocketAsyncEventArgs SendToArgs = new SocketAsyncEventArgs();
SendToArgs.SetBuffer(bytes, 0, bytes.Length); //设置要发送的数据
SendToArgs.RemoteEndPoint = ipPoint; //设置要发送的IP地址
SendToArgs.Completed += SendToAsyncCallBack; //设置完成事件
socket.SendToAsync(SendToArgs);
}
private void SendToAsyncCallBack(object s, SocketAsyncEventArgs args)
{
if (args.SocketError == SocketError.Success)
{
print("发送成功");
}
else
{
print("发送失败");
}
} -
UDP接收消息
Async
结尾异步方法首先实例化一个
SocketAsyncEventArgs
,然后设置完成异步方法后执行的回调函数
回调函数有两个参数,一个是执行异步方法的Socket
(object
类型),一个是传入到异步方法的SocketAsyncEventArgs
然后,需要通过socketAsyncEventArgs.SetBuffer()
来设置要接收消息的字节数组
通过socketAsyncEventArgs.RemoteEndPoint
来设置记录发送者的IP地址和端口号的EndPoint
在回调函数中,需要通过
socketAsyncEventArgs.SocketError
来判消息接收是否成功
通过socketAsyncEventArgs.Buffer
来获取接收到消息的字节数组
通过socketAsyncEventArgs.BytesTransferred
来获取接收到了多少字节数据1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30private byte[] cacheBytes = new byte[512];
void Start()
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
SocketAsyncEventArgs receiveFromArgs = new SocketAsyncEventArgs();
receiveFromArgs.SetBuffer(cacheBytes, 0, cacheBytes.Length); //设置要接收数据的数组
receiveFromArgs.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0); //设置用于记录发送者IP和端口号的EndPoint
receiveFromArgs.Completed += ReceiveFromAsyncCallBack; //设置完成事件
socket.ReceiveFromAsync(receiveFromArgs);
}
private void ReceiveFromAsyncCallBack(object s, SocketAsyncEventArgs args)
{
if (args.SocketError == SocketError.Success)
{
print("接收成功");
//处理消息
print(Encoding.UTF8.GetString(args.Buffer, 0, args.BytesTransferred));
Socket socket = s as Socket;
//设置从第几位开始接,最多接多少字节
args.SetBuffer(0, cacheBytes.Length);
socket.ReceiveFromAsync(args);
}
else
{
print("接收失败");
}
}
-