请教关于Overlapped IO性能低下的问题
最近写了一个事件通知模型的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;
}