我使用blocking mode的socket,在接收数据时,第一次调用recv会成功,但
只能收到一部分数据,再次调用recv()接收剩余数据时,出错,返回错误是10038
也就是无效socket,但我保证socket没有错。我甚至尝试按异步socket处理,在接收前加上下面这样一段代码来确保有数据可接收都没用!
这是为什么??????????????????
只能收到一部分数据,再次调用recv()接收剩余数据时,出错,返回错误是10038
也就是无效socket,但我保证socket没有错。我甚至尝试按异步socket处理,在接收前加上下面这样一段代码来确保有数据可接收都没用!
这是为什么??????????????????
HANDLE hEvent = WSACreateEvent();
if (hEvent != WSA_INVALID_EVENT)
{
if (WSAEventSelect(sckHTTPSocket, hEvent, FD_READ) == 0 &&
WSAWaitForMultipleEvents(1, &hEvent, FALSE, m_nRecvTimeout, FALSE) != WAIT_OBJECT_0)
{
free(pBuffer);
return NULL;
}
CloseHandle(hEvent);
}
你是不是在send成功后立即close了socket?
bool CUDPPing::Ping(LPCTSTR pStrHostName, DWORD nPingTimeout)
{ SOCKET rawSocket;
struct sockaddr_in saDest;
struct sockaddr_in saSrc;
LPHOSTENT lpHost;
CString str;
int nRet;
DWORD dwTimeSent,dwElapsed;
u_char cTTL;
long m_laddr;
//清零 rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
while (TRUE)
{
m_laddr = inet_addr((CString)pStrHostName);
if (m_laddr == INADDR_NONE)
{
lpHost = gethostbyname((CString)pStrHostName);
if (lpHost == NULL)
{
continue;
}
saDest.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr));
}
else
{
saDest.sin_addr.s_addr =m_laddr;
}
saDest.sin_family = AF_INET;
saDest.sin_port = 0;
//PING
SendEchoRequest(rawSocket, &saDest);
nRet = WaitForEchoReply(rawSocket);
if (!nRet)
{
return FALSE;
}
else
{
// 刷新回应
dwTimeSent = RecvEchoReply(rawSocket, &saSrc, &cTTL);
// 计算剩余时间
dwElapsed = GetTickCount() - dwTimeSent;
}
}
nRet = closesocket(rawSocket); return TRUE;
}int CUDPPing::WaitForEchoReply(SOCKET s)
{ struct timeval Timeout;
fd_set readfds; readfds.fd_count = 1;
readfds.fd_array[0] = s;
Timeout.tv_sec = 1;
Timeout.tv_usec = 0;
return(select(1, &readfds, NULL, NULL, &Timeout));
}int CUDPPing::SendEchoRequest(SOCKET s, LPSOCKADDR_IN lpstToAddr)
{
static ECHOREQUEST echoReq;
static nId = 1;
static nSeq = 1;
int nRet; //填充请求
echoReq.icmpHdr.Type = ICMP_ECHOREQ;
echoReq.icmpHdr.Code = 0;
echoReq.icmpHdr.Checksum = 0;
echoReq.icmpHdr.ID = nId++;
echoReq.icmpHdr.Seq = nSeq++; // 填充测试用的数据
for (nRet = 0; nRet < REQ_DATASIZE; nRet++)
echoReq.cData[nRet] = ' '+nRet; // Save tick count when sent
echoReq.dwTime = GetTickCount(); // 把数据放入包中并接受检查
echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq, sizeof(ECHOREQUEST)); //发送请求的显示信息
nRet = sendto(s, /* socket */
(LPSTR)&echoReq, /* 缓冲 */
sizeof(ECHOREQUEST),
0, /* 标志 */
(LPSOCKADDR)lpstToAddr, /* 定义 */
sizeof(SOCKADDR_IN)); /* 地址长度 */
return (nRet);
}DWORD CUDPPing::RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL)
{
ECHOREPLY echoReply;
int nRet;
int nAddrLen = sizeof(struct sockaddr_in); // 刷新请求连接的信息
nRet = recvfrom(s, // socket
(LPSTR)&echoReply, // 缓冲
sizeof(ECHOREPLY), // 缓冲大小
0, // 标志
(LPSOCKADDR)lpsaFrom, // 源地址
&nAddrLen); // 指向地址长度的指针 // 检测返回的信息 // 返回 time sent and IP TTL
*pTTL = echoReply.ipHdr.TTL; return(echoReply.echoRequest.dwTime); }u_short CUDPPing::in_cksum(u_short *addr, int len)
{ register int nleft = len;
register u_short *w = addr;
register u_short answer;
register int sum = 0; /*
* 由于十进制比较简单采用32位
* 采用可延伸的16位进制。
* 当需要时从高16位可扩展至低16位.
*/
while( nleft > 1 )
{
sum += *w++;
nleft -= 2;
} /* 如果有必要。提出一字节 */
if( nleft == 1 ) {
u_short u = 0; *(u_char *)(&u) = *(u_char *)w ;
sum += u;
} /*
* 从高16位到低16位
*/
sum = (sum >> 16) + (sum & 0xffff); /* 添加高16位到低16位 */
sum += (sum >> 16);
answer = ~sum; /* 截至16位 */
return (answer);
}
如果是,怎么解决?
Ping代码对我没用,要是Ping的话,用个IP Helper 函数一个调用就完事了。
Call WSAAsyncSelect to register for FD_CLOSE notification.
Call shutdown with how=SD_SEND.
When FD_CLOSE received, Call closesocket.
本方:
Call WSAAsyncSelect to register for FD_CLOSE notification.
Call shutdown with how=SD_SEND.
When FD_CLOSE received, call recv until zero returned, or SOCKET_ERROR.
Call closesocket.
CreateIoCompletionPort(.....)
建议你相信GetLastError()给出的错误代码和msdn的解释
这样的话,如果不是由于你自己关闭了socket,那么就是服务器方已经关闭了。
另外建议客户端使用异步,同时在SOCKET上等待FD_READ和FD_CLOSE消息,这样,应该可以确认是否对方关闭了套节字造成了错误。如果确实等到了FD_READ消息而出现10038错误,那么大概就是在数据传输过程中,对方关闭了套节字。
(小弟菜鸟,胡乱说两句,不对也别见怪哈^_^)
很奇怪,这个收到的数据长度总是这个值!我试着用 telnet www.???.com 80连接进去
然后发送 GET /index.htm HTTP/1.0
Host: www.???.com过去,telnet得到的数据就是全部index.htm页面,而我的程序就不行 :(
我要给这个另外加分了,看来100分不够,再加100分,另开贴给分。
====================================================================
HANDLE hEvent = WSACreateEvent();
if (hEvent != WSA_INVALID_EVENT)
{
if (WSAEventSelect(sckHTTPSocket, hEvent, FD_READ) == 0 &&
WSAWaitForMultipleEvents(1, &hEvent, FALSE, m_nRecvTimeout, FALSE) != WAIT_OBJECT_0)
{
free(pBuffer);
return NULL;
}
CloseHandle(hEvent);
}WSABUF buf;
buf.buf = pBuffer+iRecvSize;
buf.len = iBufferSize - iRecvSize;
DWORD curSize;
DWORD flags = 0;
int iErr = WSARecv(sckHTTPSocket, &buf, 1, &curSize, &flags, NULL, NULL);
int i = WSAGetLastError(); // 第二次执行到这里时,iErr = -1 , i = 10038
====================================================================
HANDLE hEvent = WSACreateEvent();
if (hEvent != WSA_INVALID_EVENT)
{
if (WSAEventSelect(sckHTTPSocket, hEvent, FD_READ) == 0 &&
WSAWaitForMultipleEvents(1, &hEvent, FALSE, m_nRecvTimeout, FALSE) != WAIT_OBJECT_0)
{
free(pBuffer);
return NULL;
}
CloseHandle(hEvent);
}WSABUF buf;
buf.buf = pBuffer+iRecvSize;
buf.len = iBufferSize - iRecvSize;
DWORD curSize;
DWORD flags = 0;
int iErr = WSARecv(sckHTTPSocket, &buf, 1, &curSize, &flags, NULL, NULL);
int i = WSAGetLastError(); // 第二次执行到这里时,iErr = -1 , i = 10038
是不是用了strcpy,它只是将数据拷贝到buffer出现'/0'为止?
好像采用异步I/O,数据到了接收端缓冲区,就会自动读取,不需要循环来接收
debug,看一下buffer收到的数据
我判断收到数据的长度不是用strcpy之类来判断的,而是依据 recv()的返回值来判断的。
1. socket句柄确实无效
2. select 参数有错
我估计是问题可能是第二个原因,但为什么第一次时是可以的?我程序中用到的select代码(注:前面代码中的select不影响)
=======================================================struct fd_set fdSet;
struct timeval tmvTimeout={0L,0L};
FD_ZERO(&fdSet);
FD_SET(sckHTTPSocket, &fdSet);
if ( select(0,&fdSet,NULL,NULL,&tmvTimeout)==SOCKET_ERROR)
{
。
}
这个问题不难,我应该可以帮你搞定。
而是你另外做一个服务程序,用来发送17k的数据,看用你的代码(recv)可以全部收到不?我想知道到底是因为收的网页的问题还是你的代码的问题?
大家多帮帮忙啊。
我写的每次收1k 的,即便是几GB的数据(收发文件夹)也没有过问题。帮你想.........
在BinaryTreeEx的帮助下搞定了,谢谢大家,另开贴给分!原因出在ParseResponseHeader()一句上,我的代码在检测服务器返回的HTTP头部内容时,
发现服务器返回了 Connection: close 一句便立即断开了连接,所以后面的数据没法再接收了。这100分给这里出现了的人另请fbmsf(FBM) BinaryTreeEx
到http://expert.csdn.net/Expert/topic/2475/2475669.xml?temp=.499859领分