开发完成端口服务器过程中,实现post两次完成调用的问题和最终解决

时间:2022-05-24 18:18:24

最近这两天在开发完成关口通信服务端的时候,遇到一个问题,通信协议的封装很简单,服务端同时接收的数据包分为两种,为叙述简便,分为A and B,A和B包长不相同,两种数据包没有固定包头来区分,于是只能根据包长字节数来区分。

完成端口的流程不用多说了,单句柄数据保存套接字,单IO操作数据保存重叠结构和操作类型,操作类型分为三种

RECVA   1

RECVB  2

SEND    0

我在WSAAccept接受到客户端连接之后,首先POST 一个WSARecv 接收A,投递的缓冲区长度为其对应的字节数,因为是异步,紧跟着POST 一个WSARecv接收B,投递的缓冲区长度为其对应的字节数。这两个WSARecv都在监听线程中投递。

这两个WSARecv同时使用一个单句柄数据,用不同的单IO操作数据来投递对A,B的接收请求,使用的工作线程函数是同一个。

在工作线程中判断操作类型分别处理,收到的A或者B数据,至此,整个程序似乎是没有什么问题,运行也正常接收到客户端发过来的数据,A和B分别实现了使用同一个工作线程函数来进行处理的模型。

这里有一个问题,由于根据数据包的字节数来判断包的类型,而且是在一个单句柄数据上进行的。那么有可能出现A数据和B数据接收乱的问题,   如果A字节数〉B字节数,那么有可能接收B的请求把A的部分数据也接收过来,这里就乱套了。当然这个通信协议本身设计就有问题,但设计者是个很固执的人。但我还会去测试这个问题,留待后面总结。

第二个问题是说在客户端发送完数据断开与服务端连接的时候,工作器线程的到完成通知就要closesocket,GlobalFree释放单句柄数据,单IO操作数据,问题出现了,由于一开始投递了两个WSARecv那么,收到完成通知的也是两个,第一个已经释放了相关内存,第二次释放的时候就会出现抛出无效地址的异常。如何判断是否已经释放成了解决问题的钥匙,本想通过检查地址是否0xfefe但是,在调试模式和运行模式下,这个值并非固定。所以我只好在单据柄数据结构中增加了一个isvalid的字段,第一次释放就会将之改为FALSE,第二次就不会再重复释放。