重叠I/O模型的 发送会影响 接收吗,何时发送???

ponydph 2015-03-06 12:00:59
开发TCP服务程序,采用TCP 重叠I/O模型 。
客户端不断的向服务器端发送数据,如果检测到某一个数据需要回复,则程序会自动发送给客户端确认命令。
采用三个线程, 第一个线程是接收客户端连接,并保存为全局变量,第二个线程为接收数据线程。
第三个为给客户端发送线程,目前发送要不用send 则会丢失数据,用WSASend则会导致影响WSARecv。
请看看大概是什么原因???




//接收TCP连接
DWORD WINAPI ProcAccept(LPVOID lpParameter)
{
WSADATA wsaData;
SOCKET sListen, sClient;
SOCKADDR_IN local, client;
DWORD dwThreadId;
int iaddrSize = sizeof(SOCKADDR_IN);

//// Initialize Windows Socket library
WSAStartup(0x0202, &wsaData);

// Create listening socket
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//// Bind
local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(PORT);
bind(sListen, (struct sockaddr *)&local, sizeof(SOCKADDR_IN));

// Listen
listen(sListen, 64);//3

// Create worker thread
CreateThread(NULL, 0, WorkerThread, lpParameter, 0, &dwThreadId);

HANDLE hSendCmd = (HANDLE)::CreateThread(NULL,0,ProcSendCmd,lpParameter,0,NULL);

while (!g_theadNET.exit)
{
// Accept a connection
sClient = accept(sListen, (struct sockaddr *)&client, &iaddrSize);
g_CliSocketArr[g_iTotalConn] = sClient;
g_mapAddr.SetAt(sClientIP,g_iTotalConn);


//通过两种方式得到
// Allocate a PER_IO_OPERATION_DATA structure
g_pPerIODataArr[g_iTotalConn] = (LPPER_IO_OPERATION_DATA)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(PER_IO_OPERATION_DATA));
g_pPerIODataArr[g_iTotalConn]->Buffer.len = MSGSIZE; //接收缓冲长度
g_pPerIODataArr[g_iTotalConn]->Buffer.buf = g_pPerIODataArr[g_iTotalConn]->szMessage; //接收缓冲区域
//创建接收数据事件,绑定该socket
g_CliEventArr[g_iTotalConn] = g_pPerIODataArr[g_iTotalConn]->overlap.hEvent = WSACreateEvent();

// 异步该socket接收数据,即立刻返回,等待事件信号状态。
WSARecv(
g_CliSocketArr[g_iTotalConn],
&g_pPerIODataArr[g_iTotalConn]->Buffer,
1,
&g_pPerIODataArr[g_iTotalConn]->NumberOfBytesRecvd,
&g_pPerIODataArr[g_iTotalConn]->Flags,
&g_pPerIODataArr[g_iTotalConn]->overlap,
NULL);

g_iTotalConn++; //连接数加1
}

closesocket(sListen);

//////////////////////////
WSACleanup();

return 0;
}


//接收TCP连接数据
DWORD WINAPI WorkerThread(LPVOID lpParam)
{
CMainFrame* pMain=(CMainFrame*)lpParam;
///////////////////////////////////////////
int ret, index;
DWORD cbTransferred;


while (!g_theadNET.exit)
{
ret = WSAWaitForMultipleEvents(g_iTotalConn, g_CliEventArr, FALSE, 1000, FALSE); //等待事件信号,1s超时
if (ret == WSA_WAIT_FAILED || ret == WSA_WAIT_TIMEOUT)
{
continue;
}

index = ret - WSA_WAIT_EVENT_0; //取信号事件的索引号
WSAResetEvent(g_CliEventArr[index]); //将事件重置

WSAGetOverlappedResult( //返回指定套接口上一个重叠操作的结果。
g_CliSocketArr[index], //调用重叠操作时socket
&g_pPerIODataArr[index]->overlap, //指向调用重叠操作时指定的WSAOVERLAPPED结构
&cbTransferred, //接收实际数据长度
TRUE, //指定函数是否等待挂起的重叠操作结束
&g_pPerIODataArr[g_iTotalConn]->Flags); //该变量存放完成状态的附加标志位

if (cbTransferred == 0) //接收为数据长度为0,表示socket已经被关闭
{
// The connection was closed by client
Cleanup(index);
}
else
{

BYTE arr[MSGSIZE];
for(int i=0;i<cbTransferred;i++)
{
arr[i]=(BYTE)g_pPerIODataArr[index]->szMessage[i];
//printf("%02X ",arr[i]);
}

// Launch another asynchronous operation
WSARecv(
g_CliSocketArr[index],
&g_pPerIODataArr[index]->Buffer,
1,
&g_pPerIODataArr[index]->NumberOfBytesRecvd,
&g_pPerIODataArr[index]->Flags,
&g_pPerIODataArr[index]->overlap,
NULL);
}
}

return 0;
}

//服务器端发送客户端线程
DWORD WINAPI ProcSendCmd(LPVOID lpParameter)
{
while(true)
{
if(有数据)
{
int index=查找对应的连接;
int a=send(g_CliSocketArr[index], (char*)buf,len, 0);
}
}
}

//程序在运行时发现,如果用send函数发送,则会丢失数据,查看返回值 也标示发送成功了,但就是没收到。

如果用 WSASend发送,重叠结构用接收时候生成的同一结构,则客户端不发送后,服务器端还有数据,请问是什么原因??

int a=WSASend(g_CliSocketArr[index],&DataBuf,1,&SendBytes,0,&g_pPerIODataArr[index]->overlap,NULL);


...全文
140 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
ponydph 2015-03-10
  • 打赏
  • 举报
回复
数据长度没有问题,成功就是有返回,不成功就是没有。 现在是不断接收的同时,发送数据时,有的能收到,有的收不到。 一般的例子是,接收到数据后,就立刻把接收到的数据返回到客户端。 我返回时在单独的发送线程,用send函数。 接收在一个线程,这和都在一个线程内处理是否有关系?
ponydph 2015-03-09
  • 打赏
  • 举报
回复
继续 请教 、!!
Eleven 2015-03-09
  • 打赏
  • 举报
回复
引用 8 楼 ponydph 的回复:
[quote=引用 7 楼 zjz8011com 的回复:] 重叠IO要用WSASocket创建,并且最后一个参数需要设置成WSA_FLAG_OVERLAPPED
我看资料 用socket创建,默认就是社会自了 上述那个参数。 而调用WSASocket时则需要设置 。 主要是发送的问题, 普通的例子都是接收完成之后,直接发回到客户端。 我实现的功能是 服务器需要时才发给客户端,这样是在单独的线程里面,等待,查询命令队列有命令时才发送的。 通过判断send()返回值 也是和发动的长度一致,但就是没有返回来。 不知道什么原因??? [/quote] 你接收端是否有数据返回,看看返回值是什么?数据长度是多少?和发送端要求的是否一致?不一致的情况下你又是如何处理的?继续循环接收还是怎样?
赵4老师 2015-03-06
  • 打赏
  • 举报
回复
要不要先参考MSDN中自带的相关例子代码?
lougd 2015-03-06
  • 打赏
  • 举报
回复
socket是双工的,发送和接受不会影响。
ponydph 2015-03-06
  • 打赏
  • 举报
回复
引用 7 楼 zjz8011com 的回复:
重叠IO要用WSASocket创建,并且最后一个参数需要设置成WSA_FLAG_OVERLAPPED
我看资料 用socket创建,默认就是社会自了 上述那个参数。 而调用WSASocket时则需要设置 。 主要是发送的问题, 普通的例子都是接收完成之后,直接发回到客户端。 我实现的功能是 服务器需要时才发给客户端,这样是在单独的线程里面,等待,查询命令队列有命令时才发送的。 通过判断send()返回值 也是和发动的长度一致,但就是没有返回来。 不知道什么原因???
zjz8011com 2015-03-06
  • 打赏
  • 举报
回复
重叠IO要用WSASocket创建,并且最后一个参数需要设置成WSA_FLAG_OVERLAPPED
ponydph 2015-03-06
  • 打赏
  • 举报
回复
继续请教,使用重叠模型 发送的问题。 是用send 还是WSASend,是否需要重置I/O结构。
赵4老师 2015-03-06
  • 打赏
  • 举报
回复
引用 4 楼 ponydph 的回复:
[quote=引用 2 楼 zhao4zhong1 的回复:] 要不要先参考MSDN中自带的相关例子代码?
请问 发送和接收会有影响吗,采用重叠I、O模型的时候。[/quote] 我也没具体编译链接调试过。 MSDN98_1.ISO http://pan.baidu.com/s/1dDF41ix, MSDN98_2.ISO http://pan.baidu.com/s/1bnGo0Vl 先下载安装MSDN98,再参考 MSDN98\SAMPLES\VC98\SDK\NETDS\WINSOCK\DT_DLL\HANDLERS.CPP ?
ponydph 2015-03-06
  • 打赏
  • 举报
回复
引用 2 楼 zhao4zhong1 的回复:
要不要先参考MSDN中自带的相关例子代码?
请问 发送和接收会有影响吗,采用重叠I、O模型的时候。
ponydph 2015-03-06
  • 打赏
  • 举报
回复
引用 1 楼 u011391040 的回复:
socket是双工的,发送和接受不会影响。
但是 我直接在另一个线程中 用send函数,客户端会有收不到的情况。 不知道是没有发出? 或者明明只发送了一次,在接收端却收到了多次?

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧