最近在移植项目以前的功能到新项目时,遇到了一个很奇怪的问题:在创建完成端口之后,投递WSARecv的时候,一直返回10014.
window的错误码官方解释:
//
// MessageId: WSAEFAULT
//
// MessageText:
//
// The system detected an invalid pointer address in attempting to use a pointer argument in a call.
//
#define WSAEFAULT 10014L
从这个错误码的解释来看,应该是传参错误!首先就是看是否有空指针,再者就是分析逻辑了:
一般在使用完成端口时,通常都是在服务器端使用:监听端口accept的时候创建一个添加到完成端口中。但是在这里是在客户端使用的完成端口:socket连接是已经建立好的,在某种情况下,如果要大量、长时间的接收数据才考虑使用完成端口接收数据,否则就直接读socket。
在验证了这些方案的可行性之后,还是回到了最基本的API上,该函数的原型:
int
WSAAPI
WSARecv(
IN SOCKET s,
__in_ecount(dwBufferCount) __out_data_source(NETWORK) LPWSABUF lpBuffers,
IN DWORD dwBufferCount,
__out_opt LPDWORD lpNumberOfBytesRecvd,
IN OUT LPDWORD lpFlags,
__in_opt LPWSAOVERLAPPED lpOverlapped,
__in_opt LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
此时,从网上找了一下其它人的经验,大致分成两种情况:
1.参数传递错误:将
lpFlags字段直接传成了0.
当然我不可能原型都不看就调用,因此排出这种方法。
2.
lpBuffers需要4字节对齐
公司的产品做得比较早,以前为了节约内存都是采用的1字节对齐,因此如果真是有这个限制,那很可能就是这个原因。
而该部分代码使用了一个大型的嵌套结构体,在之前的代码中没有这个问题,而在移植后的代码有这个问题——之前的代码刚刚好是4字节对齐了?
要怎么计算现在到底是不是4字节对齐呢,难道要笔一个一个加,或者是用计算器算?
联想到VS编译器采用的是16进制,而需要的是4字节对齐,那么是否只需要位数是4的倍数就行了?比如对于10进制数,如果位数是5、0则都能被5整除,这只是猜想怎么证明呢?
对于一个16进制整数,如果它只有一位,就是我们要证明的——明显符合。
当其多于一位时,可以表示为k=y*16x+z,其中z为个位,y>=0,x>0,k为该数。从而k=y*16x-1*16+z.故只要能被16整除的数,都可以只看最低位。
比如:对于16机制的数k,K能被2、4、8整除 等价于 K的最低位能被2、4、8整除。
进一步,该结论可以推广到任何进制:
对于K进制的数,如果要判断K能被其某个最大公约数整除,只需要判断其最低位能否被该最大公约数整除。比如十进制可以判断的是2、5
PS:最初我也是拿计算器算的,只是当时有这种想法,回家的路上想到了,早上来做个记录!
——2017.9.7
阅读(1536) | 评论(0) | 转发(0) |