对Socket通信中BeginReceive方法的一些理解

@TOC加粗样式

对Socket通信中BeginReceive方法的一些理解

在学习Unity的网络通信的时候,客户端和服务器端使用Socket通信。其中用到了不少Socket的方法。

先看看Receive方法,Receive方法的主要参数是传入一个接受数据的byte数组。查看文档可以得知:如果没有可读取的数据,则Receive方法将一直处于阻止状态,直到数据可用,除非使用 Socket::ReceiveTimeout 设置了超时值。 如果超过超时值,Receive 调用将引发 SocketException。

再看看BeginReceive方法,该方法主要参数也有一个用于接受数据的byte数组。还有一个重要的参数是,一个AsyncCallBack委托。我们把它简单的理解为需要传入一个接受数据的回调函数。
我们调用BeginReceive的时候,系统会开启一个独立的线程(使用线程池),用以执行回调函数及对EndReceive的阻塞(block),直到EndReceive从socket的缓冲区中读到数据或者socket引发异常。

简单的理解为,如果在回调函数调用之前使用EndReceive方法,那么线程会被阻塞,直到读到了数据,或者发生错误。所以,最常用的写法是,在回调函数中使用EndReceive方法。EndReceive方法是必须要使用的。EndReiceive方法有一个返回值,代表接受数据的长度。
那么,回调函数何时会调用呢?文档中也没有详细说明。
我做了一些简单的测试。
服务端器端定义了一个很大的byte数组,作为接受数据的buffer。
Alt
我向服务器端发送消息,并将消息打印。
Alt
客户端向服务器端发送了三次消息,虽然都远远没有达到buffer的长度,但还是执行了回调。这说明了,如果缓冲区够大,接受到一次消息哪怕没填满缓冲区,也执行一次回调。
那么缓冲区如果太小呢。
首先我在发送数据的时候,对数据包进行了封装,将原始包的长度,添加到了包最前面,作为包头。在服务器端,收包时,先读取包头,如果收到的包体长度,比包头的数据短,则继续调用BeginReceive,继续收包,(并将收到的数据从buffer中取出和之前收到的数据,连在一起)直到收到的包体长度大于等于包体中指定的长度。
先调整服务器端接受数据的缓冲区。
Alt
我仅向服务器端发送了一次数据。
Alt
可以看到,因为缓冲区长度太小,执行了4次回调(并不是一个BeginReceive的回调函数会执行4次,而是因为我执行了4次BeginReiceive)。这说明了,当数据将缓冲区填满之后,会执行回调函数。
总的来说,可以抽象理解为:
传入BeginReceive的buffer参数相当于舀水勺(大小我们自己定义)。当我们调用BeginReceive方法时(开启新的线程),就用舀水勺去水池(socket接受数据的缓冲区)中舀水,没有水则等待。舀一次之后,就会调用回调函数(不管舀了多少),在回调函数中,(通过EndReceive,知道我们舀了多少水),我们自己决定对水勺中的水做什么(即对数据的处理),然后继续舀水(在回调函数中调用BeginReceive),若池中有数据,继续舀,没有就等待。其中,每次重新去舀水的时候,我们都是用的空的水勺,之前水勺中的水被清空了。

原文链接: https://blog.csdn.net/lishengxu159/article/details/80098938.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值