请教关于Overlapped IO性能低下的问题

watalou 2010-06-23 11:20:06
最近写了一个事件通知模型的Overlapped IO程序。为了只是印证Overlapped IO的性能,不引入磁盘IO,因此程序中发送的内容均是直接从内存中发送(减少读写本地磁盘IO的操作)。但其中存在一些问题,实在不明白个中原因。因此把代码贴出来请大家帮指教。

实现的大概思路是:
server进行监听,只要client连接上server,server端就向client端发送数据。发送的数据均是从内存中发送。为了印证数据发送的正确性,在server端,为内存的前几个字节写入一个整型变量,在client端将收到的变量写入一个日志文件(logfile)。
问题:
1)实现后的程序性能较低,通过windows任务管理器查看,从“联网”选项页中的“网络应用”中发现只用到了小于30%的性能。而此时CPU的利用率是10%左右,因此可以排队CPU的瓶颈问题。
2)通过查看logfile中的数据,可以发现有很多数据未正确接收。理想情况下,比如server发送1000次内存数据,则在client端的logfile中,应该出现1-1000这些数据(顺序可以乱序,因为是异步处理,不能保证顺序)。但实际情况是数据中很多数字没有出现,即表明未正确接收。

我的平台:
windows XP SP3
Visual Studio 2010

------server端代码----
#include <winsock2.h>
#include <ws2tcpip.h>
#include <mswsock.h>
#include <windows.h>
#include <iostream>

#pragma comment(lib,"ws2_32.lib")

using namespace std;

#define LISTEN_QSIZE 10

int main(int argc, char* argv[])
{
WSADATA WSAData;
SOCKET sd, acceptSock;
sockaddr_in pin;
int ret;
DWORD RecvBytes = 0, dFlags = 0;


int count;
WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
int pktSize;
int bufNum;
int portNum;

if (argc < 3)
{
/*
pktSize: 每次发送的报文大小,是指payload的大小
count: 发送报文的次数。 pktSize*count即为总发送的字节数
portNum: 监听端口号
*/
cout << "IOsender pktSize count portNum" << endl;
return -1;
}
else
{
pktSize = atoi(argv[1]);
count = atoi(argv[2]);
portNum = atoi(argv[3]);
}
bufNum = 5;

//ret = WSAStartup(0x101, &WSAData);
ret = WSAStartup(MAKEWORD(2, 2), &WSAData);
if (ret != 0)
{ cout <<"socket initializaiton error" << endl;
return -1;
}

sd = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (ret == SOCKET_ERROR)
{
cout << "socket creation error" << endl;
return -1;
}

memset(&pin, 0, sizeof(pin));
pin.sin_family = AF_INET;
pin.sin_addr.s_addr = htonl(INADDR_ANY);
pin.sin_port = htons(portNum);


/* step 2: bind address */
ret = bind (sd, (struct sockaddr *)&pin, sizeof(struct sockaddr_in));
if (ret == SOCKET_ERROR)
{
cout << "socket bind error" << endl;
closesocket(sd);
return -1;
}

/* step 3: listen */
ret = listen (sd, LISTEN_QSIZE);
if (ret == SOCKET_ERROR)
{
cout << "socket listen error" << endl;
closesocket(sd);
return -1;
}
printf("Waiting for client to connect...\n");


/* step 4: accept */
acceptSock = accept(sd, NULL, NULL);
if (acceptSock == INVALID_SOCKET)
{
cout << "socket accept error: " << GetLastError() << endl;
closesocket(sd);
return -1;
}
else
{
cout << "accept succeed" << endl;
}

WSAOVERLAPPED* pSendOverlapped = new WSAOVERLAPPED[bufNum];
WSABUF* pDataBuf = new WSABUF[bufNum];

for (int i=0; i<bufNum; i++){
ZeroMemory(&(pSendOverlapped[i]), sizeof(WSAOVERLAPPED));
EventArray[i] = WSACreateEvent();
if (EventArray[i] == NULL)
{
cout <<"WSACreateEvent failed: " <<WSAGetLastError() <<endl;
WSACleanup();
return -1;
}
pSendOverlapped[i].hEvent = EventArray[i];
pDataBuf[i].len = pktSize;
pDataBuf[i].buf = new char[pktSize];
}

int seq = 0;
int iBuf;
int Flags = 0;
int Index;
int i = 0;

for (i=0; i<bufNum; i++){
*(int*)pDataBuf[i].buf = seq++;
ret = WSASend(acceptSock, &pDataBuf[i], 1, NULL, Flags, &pSendOverlapped[i], NULL);

if (ret == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING)
{
cout << "asyn send error: " << WSAGetLastError() << endl;
}
}

count -= bufNum;

while (count--)
{
Index = WSAWaitForMultipleEvents(bufNum, EventArray, FALSE, WSA_INFINITE, FALSE);
if (Index == WSA_WAIT_FAILED)
{
cout <<"WSAWaitForMultipleEvents failed:" <<WSAGetLastError() <<endl;
return -1;
}
iBuf = Index - WSA_WAIT_EVENT_0;


WSAGetOverlappedResult(acceptSock, &(pSendOverlapped[iBuf]), &RecvBytes, FALSE, &dFlags);
if (RecvBytes == 0) {
printf("Closing Socket %d\n", acceptSock);
closesocket(acceptSock);
WSACloseEvent(EventArray[iBuf]);
return 0;
}

// Reset the signaled event
WSAResetEvent(EventArray[iBuf]);
ZeroMemory(pDataBuf[iBuf].buf,pktSize);
pDataBuf[iBuf].len = pktSize;
pSendOverlapped[iBuf].hEvent = EventArray[iBuf];
*(int*)pDataBuf[iBuf].buf = seq++;

ret = WSASendTo(acceptSock, &pDataBuf[iBuf], 1, NULL, Flags, (const sockaddr *)&pin, sizeof(pin), &pSendOverlapped[iBuf], NULL);

if ( (ret == SOCKET_ERROR) && (WSAGetLastError() != WSA_IO_PENDING) )
{
cout << "asyn send error: " << WSAGetLastError() << endl;
}
}

closesocket(acceptSock);
closesocket(sd);
cout << "done! " << endl;
return 0;
}


----client端代码----
/*
问题:1)本程序如何退出?好象没有退出的条件。
*/

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <iostream>
#include <fstream>
#include <windows.h>

#pragma comment(lib,"ws2_32.lib")

using namespace std;

SOCKET sd;
sockaddr_in pin, senderaddr;
int addrsize;

WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];

DWORD RecvBytes = 0;
DWORD Flags = 0;

int ret,err;
ofstream logfile("logfile.txt");

int main(int argc, char* argv[])
{
ULONG servAddr;
int pktSize;
int bufNum;
int portNum;
struct sockaddr_in srv_addr;


if (argc < 3)
{
cout << "IOreceiver pktSize serverAddr portNum" << endl;
return -1;
}
else
{
pktSize = atoi(argv[1]);
servAddr = inet_addr(argv[2]);
portNum = atoi(argv[3]);
}
bufNum = 10;

WSADATA WSAData;
ret = WSAStartup(MAKEWORD(2, 2), &WSAData);
if (ret != 0)
{
cout <<"socket initializaiton error" << endl;
return -1;
}

sd = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (sd < 0)
{
cout << "socket creation error" << endl;
return -1;
}

#define BIG_RCV_BUF 1
#if BIG_RCV_BUF
int nZero = 1*1024*1024;
ret = setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (char *)&nZero, sizeof(int));
if (ret != 0)
{
cout << "setsockopt SO_RCVBUF error: "<< WSAGetLastError() << endl;
closesocket(sd);
return -1;
}
#endif


srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons (portNum);
srv_addr.sin_addr.S_un.S_addr = servAddr;


ret = connect (sd, (struct sockaddr *)&srv_addr, sizeof(struct sockaddr_in));
if (ret == SOCKET_ERROR)
{
cout << "socket connect error: " << WSAGetLastError() << endl;
closesocket(sd);
return -1;
}
else
{
cout << "socket connect succeed" << endl;
}



WSAOVERLAPPED* pRecvOverlapped = new WSAOVERLAPPED[bufNum];
WSABUF* pDataBuf = new WSABUF[bufNum];

for (int i=0; i<bufNum; i++){
ZeroMemory(&(pRecvOverlapped[i]), sizeof(WSAOVERLAPPED));
EventArray[i] = WSACreateEvent();
if (EventArray[i] == NULL)
{
cout <<"WSACreateEvent failed: " <<WSAGetLastError() <<endl;
WSACleanup();
return -1;
}
pRecvOverlapped[i].hEvent = EventArray[i];
pDataBuf[i].len = pktSize;
pDataBuf[i].buf = new char[pktSize];
}

for (int i=0; i<bufNum; i++){
ret = WSARecvFrom(sd, &(pDataBuf[i]), 1, &RecvBytes, &Flags, (sockaddr*)&senderaddr, &addrsize, &(pRecvOverlapped[i]), NULL);
if (ret == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING)
{
cout << "asyn receive error" << WSAGetLastError() << endl;
}
}

int iBuf;

while (1)
{
DWORD Index;
Index = WSAWaitForMultipleEvents(bufNum, EventArray, FALSE, WSA_INFINITE, TRUE);
if (Index == WSA_WAIT_FAILED)
{
cout <<"WSAWaitForMultipleEvents failed:" << WSAGetLastError() <<endl;
return -1;
}
iBuf = Index - WSA_WAIT_EVENT_0;
WSAGetOverlappedResult(sd, &(pRecvOverlapped[iBuf]), &RecvBytes, FALSE, &Flags);
if (RecvBytes == 0) {
printf("Closing Socket %d\n", sd);
closesocket(sd);
WSACloseEvent(EventArray[iBuf]);
return 0;
}
//记录接收到的数据
logfile <<*(int*)pDataBuf[iBuf].buf <<endl;


// Reset the signaled event
WSAResetEvent(EventArray[iBuf]);
pRecvOverlapped[iBuf].hEvent = EventArray[iBuf];
ZeroMemory(pDataBuf[iBuf].buf,pktSize);
pDataBuf[iBuf].len = pktSize;



ret = WSARecvFrom(sd, &(pDataBuf[iBuf]), 1, &RecvBytes, &Flags, (sockaddr*)&senderaddr, &addrsize, &(pRecvOverlapped[iBuf]), NULL);
if (ret == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING)
{
cout << "asyn receive error: " << WSAGetLastError() << endl;
}
}

return 0;
}
...全文
108 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
watalou 2010-06-29
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 macrojj 的回复:]

没有投递请求啊。

Windows网络编程上的例子 跟你差不多。你可以看看
[/Quote]
可否详细说明一下,什么叫“没有投递请求”?请求的投递都是在循环中完成的。
macrojj 2010-06-29
  • 打赏
  • 举报
回复
没有投递请求啊。

Windows网络编程上的例子 跟你差不多。你可以看看
  • 打赏
  • 举报
回复
重叠IO以前在IOCP中接触过,

但我的应用效率没有你的这么低

你的代码太多了

你自己可以单步调试一下

逻辑问题吧

重叠IO本身事没有问题的


chenyu2202863 2010-06-29
  • 打赏
  • 举报
回复
认真看看书吧
watalou 2010-06-29
  • 打赏
  • 举报
回复
怎么没有人回答呢?

3,881

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 其它技术问题
社区管理员
  • 其它技术问题社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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