编写的一个程序,C/S模式,server完成端口。
client发送登录信令,server接收并发送回复信令,然后client接收回复信令并发送用户信息信令,这一步server没有接收到数据。问题一:
是否在每次server接收完数据后都要清空接收缓冲区??也就是要清空单操作数据??原来代码太复杂,但主要与以下代码相似,而client端的代码是我自己写来测试的
问题二:
server中的
if (PerIoData->BytesRECV > PerIoData->BytesSEND)判断有什么用,能说说吗?情况1,server中else注释掉,client中sleep不注释,server端接收没问题。
情况2,server中else注释掉,client中sleep注释,server端接收有问题,只受到第一个数据。
情况3,server中else不注释,client中sleep注释,server端接收没问题。
《windows网络编程》中的代码修改如下:server中的线程函数:
THREAD_PRO IOCompletionThd(LPVOID CompletionPortID)
{
HANDLE CompletionPort = (HANDLE) CompletionPortID;
DWORD BytesTransferred;
LPOVERLAPPED Overlapped;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
DWORD SendBytes, RecvBytes;
DWORD Flags;
while(TRUE)
{
if (GetQueuedCompletionStatus(CompletionPort, &BytesTransferred,
(LPDWORD)&PerHandleData, (LPOVERLAPPED *) &PerIoData, INFINITE) == 0)
{
;//error
} if (BytesTransferred == 0)
{
;//error
if (::closesocket(PerHandleData->Socket) == SOCKET_ERROR)
{
;//error
} GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
} // Check to see if the BytesRECV field equals zero. If this is so, then
// this means a WSARecv call just completed so update the BytesRECV field
// with the BytesTransferred value from the completed WSARecv() call. if (PerIoData->BytesRECV == 0)
{
PerIoData->BytesRECV = BytesTransferred;
PerIoData->BytesSEND = 0;
}
else
{
PerIoData->BytesSEND += BytesTransferred;
} if (PerIoData->BytesRECV > PerIoData->BytesSEND)
{ // Post another WSASend() request.
// Since WSASend() is not gauranteed to send all of the bytes requested,
// continue posting WSASend() calls until all received bytes are sent.
printf("recv %s\n",PerIoData->DataBuf.buf);
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED)); PerIoData->DataBuf.buf = PerIoData->Buffer + PerIoData->BytesSEND;
PerIoData->DataBuf.len = PerIoData->BytesRECV - PerIoData->BytesSEND; if (!CSock::Send(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &SendBytes, 0,
&(PerIoData->Overlapped)))
{
;//error
}
}
/* else这段注释与不注释结果不一样
else
{
PerIoData->BytesRECV = 0; // Now that there are no more bytes to send post another WSARecv() request. Flags = 0;
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED)); PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer; if (!CSock::Recv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,
&(PerIoData->Overlapped)))
{
;//error
}
}
*/
}
return 0;
}client的线程函数中的一个循环发送代码段:
for(i=0;i<dwCount;i++)
{
ret=::send(sClient,szMessage,sizeof(szMessage),0);
if(ret==0)
break;
else if(ret==SOCKET_ERROR)
{
cout << "send failed " << ::GetLastError() << endl;
break;
}
cout << "send " << ret << "bytes.\n";
// ::Sleep(1000);//sleep注释与否代码不一样
}
client发送登录信令,server接收并发送回复信令,然后client接收回复信令并发送用户信息信令,这一步server没有接收到数据。问题一:
是否在每次server接收完数据后都要清空接收缓冲区??也就是要清空单操作数据??原来代码太复杂,但主要与以下代码相似,而client端的代码是我自己写来测试的
问题二:
server中的
if (PerIoData->BytesRECV > PerIoData->BytesSEND)判断有什么用,能说说吗?情况1,server中else注释掉,client中sleep不注释,server端接收没问题。
情况2,server中else注释掉,client中sleep注释,server端接收有问题,只受到第一个数据。
情况3,server中else不注释,client中sleep注释,server端接收没问题。
《windows网络编程》中的代码修改如下:server中的线程函数:
THREAD_PRO IOCompletionThd(LPVOID CompletionPortID)
{
HANDLE CompletionPort = (HANDLE) CompletionPortID;
DWORD BytesTransferred;
LPOVERLAPPED Overlapped;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
DWORD SendBytes, RecvBytes;
DWORD Flags;
while(TRUE)
{
if (GetQueuedCompletionStatus(CompletionPort, &BytesTransferred,
(LPDWORD)&PerHandleData, (LPOVERLAPPED *) &PerIoData, INFINITE) == 0)
{
;//error
} if (BytesTransferred == 0)
{
;//error
if (::closesocket(PerHandleData->Socket) == SOCKET_ERROR)
{
;//error
} GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
} // Check to see if the BytesRECV field equals zero. If this is so, then
// this means a WSARecv call just completed so update the BytesRECV field
// with the BytesTransferred value from the completed WSARecv() call. if (PerIoData->BytesRECV == 0)
{
PerIoData->BytesRECV = BytesTransferred;
PerIoData->BytesSEND = 0;
}
else
{
PerIoData->BytesSEND += BytesTransferred;
} if (PerIoData->BytesRECV > PerIoData->BytesSEND)
{ // Post another WSASend() request.
// Since WSASend() is not gauranteed to send all of the bytes requested,
// continue posting WSASend() calls until all received bytes are sent.
printf("recv %s\n",PerIoData->DataBuf.buf);
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED)); PerIoData->DataBuf.buf = PerIoData->Buffer + PerIoData->BytesSEND;
PerIoData->DataBuf.len = PerIoData->BytesRECV - PerIoData->BytesSEND; if (!CSock::Send(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &SendBytes, 0,
&(PerIoData->Overlapped)))
{
;//error
}
}
/* else这段注释与不注释结果不一样
else
{
PerIoData->BytesRECV = 0; // Now that there are no more bytes to send post another WSARecv() request. Flags = 0;
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED)); PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer; if (!CSock::Recv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,
&(PerIoData->Overlapped)))
{
;//error
}
}
*/
}
return 0;
}client的线程函数中的一个循环发送代码段:
for(i=0;i<dwCount;i++)
{
ret=::send(sClient,szMessage,sizeof(szMessage),0);
if(ret==0)
break;
else if(ret==SOCKET_ERROR)
{
cout << "send failed " << ::GetLastError() << endl;
break;
}
cout << "send " << ret << "bytes.\n";
// ::Sleep(1000);//sleep注释与否代码不一样
}
解决方案 »
- 有关MSComm控件,接收数据的问题?
- 很基础的问题 10转2
- release 和 debug 的设置,急急急急急急急急急急急急
- 串口通信中通过MSCOMM控件发送数据和接受数据所用到的缓存地址是同一个么?
- ***********小妹刚学VC,VC操作Oracle,_RecordsetPtr型变量rsd,rsd执行Open,取出数据,执行AddNew时报措说当前Recordset不支持更新操
- 数据接收问题.....100分大奉送....不够再开贴送分
- 高分求代理
- 初学VB,问下为什么有的MFC类派生出来无法使用呢?
- combo box中的选项怎么清除?
- VC++应用程序能在WIN98平台上运行而不能在WIN2000上运行
- 微软的FTP API是否提供了修改Socket的功能? 我的程序需要对使用的Socket做一些设置
- CDHtmlDialog直接显示HTML的问题
1.主要看你接收的数据做啥.如果只是接收数据,然后啥都不用做了,那自然清空没问题,但如果要保存到文件呀或做其它操作,你得完成这些操作才能清空.
2.if (PerIoData->BytesRECV > PerIoData->BytesSEND)判断有什么用,能说说吗?
那是接收到的数据长度大于发送出去的,那就是接收到的数据还没发送完,还得继续发.
顶
你的代码,应该是接收到数据后,然后再发送出去.但发送完后,你没有继续有WSARecv()的投递,自然不可能再接收到数据.上面注释掉的代码,就是检查已发送完,然后清空buff,继续再接收的代码.
WSARecv SWASend 才能继续触发完成端口的工作者线程.
清空buff只是一个好的habit,buff不清空一样可以投递进去接数据.
清空buff只是一个好的habit,buff不清空一样可以投递进去接数据.
client是什么网络模型?
还有你完成端口 LPPER_IO_OPERATION_DATA结构帖出来
typedef struct
{
OVERLAPPED Overlapped;
WSABUF DataBuf;
CHAR Buffer[TAGSIZE];
DWORD BytesSEND;
DWORD BytesRECV;
} PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;
//单句柄数据
typedef struct
{
SOCKET Socket;
} PER_HANDLE_DATA, * LPPER_HANDLE_DATA;
if (PerIoData->BytesRECV > PerIoData->BytesSEND)以及下面的else与包粘连有关,好像是解决包粘连问题的
抱歉,搞错~!
明白你的程序是什么意思了,就是把所有收到的数据全部转发出去~!
那么它是通过BytesRECV 和BytesSEND的大小来决定下一步的io操作的,这两个值之全程累加的
如果收大于发,那就该send出去
否则就该继续recv了
server的工作线程在执行GetQueuedCompletionStatus后取得995错误码,怎么解决,上网搜过,得知可能是socket销毁引起,但是检查代码没错阿。请教大家!!!!