织梦CMS - 轻松建站从此开始!

罗索

一个完成端口的例子

罗索客 发布于 2007-08-27 17:27 点击:次 
完成端口是基于Windows 重叠IO 的 一种IO 管理模型,提供了最高的效率. 下面是练习使用的一个例子.服务器为别人所写.我只是消化了一下.为了配合测试,写了一个小小的客户端. 都放在这里,加深自己的记忆吧.
TAG:

完成端口是基于Windows 重叠IO 的 一种IO 管理模型,提供了最高的效率. 下面是练习使用的一个例子.服务器为别人所写.我只是消化了一下.为了配合测试,写了一个小小的客户端. 都放在这里,加深自己的记忆吧.
服务器代码:
// IOCP.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#define _WIN32_WINNT 0x0500
#include <cstdlib>
#include <clocale>
#include <ctime>
#include <iostream>
#include <vector>
#include <algorithm>
#include <WinSock2.h>
#include <mswsock.h>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "mswsock.lib")
const int MAX_BUFFER_SIZE = 1024;
const int PRE_SEND_SIZE = 1024;
const int QUIT_TIME_OUT = 3000; //退出时主线程分80次Sleep完3000MS, 以等待workThread退出
const int PRE_DOT_TIMER = QUIT_TIME_OUT / 80;
typedef enum{IoTransFile, IoSend, IoRecv, IoQuit} IO_TYPE;
typedef struct
{
SOCKET hSocket;
SOCKADDR_IN ClientAddr;
} PRE_SOCKET_DATA, *PPRE_SOCKET_DATA;
typedef struct
{
OVERLAPPED oa;
WSABUF DataBuf;
char Buffer[MAX_BUFFER_SIZE];
IO_TYPE IoType;
} PRE_IO_DATA, *PPRE_IO_DATA;
typedef vector<PPRE_SOCKET_DATA> SocketDataVector;
typedef vector<PPRE_IO_DATA> IoDataVector;
SocketDataVector gSockDataVec;
IoDataVector gIoDataVec;
CRITICAL_SECTION csProtection;
char *TimeNow(void)
{
time_t t = time(NULL);
tm *localtm = localtime(&t);
static char timemsg[512]={0};
strftime(timemsg, 512, "%Z: %B %d %X %Y", localtm);
return timemsg;
}
BOOL TransFile(PPRE_IO_DATA pIoData, PPRE_SOCKET_DATA pSocketData, DWORD dwNameLen)
{
pIoData->Buffer[dwNameLen-1] = ''\\0'';
HANDLE hFile = CreateFile(pIoData->Buffer, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
BOOL bRet = FALSE;
if (hFile != INVALID_HANDLE_VALUE)
{
cout<<"Transmit File"<<pIoData->Buffer<<"to client"<<endl;
pIoData->IoType = IoTransFile;
memset(&pIoData->oa, 0, sizeof(OVERLAPPED));
*reinterpret_cast<HANDLE*>(pIoData->Buffer) = hFile; // 此处保存句柄是为了在传输完毕后关闭文件
TransmitFile(pSocketData->hSocket, hFile, GetFileSize(hFile, NULL),
PRE_SEND_SIZE, reinterpret_cast<LPOVERLAPPED>(pIoData),
NULL, TF_USE_SYSTEM_THREAD);
bRet =(WSAGetLastError() == WSA_IO_PENDING);
}
else
cout<<"Transmit File"<<"Error:"<<GetLastError()<<endl;
return bRet;
}
DWORD WINAPI ThreadProc(LPVOID IocpHandle)
{
DWORD dwRecv = 0;
DWORD dwFlags = 0;
HANDLE hIocp = reinterpret_cast<HANDLE> (IocpHandle);
DWORD dwTransCount = 0;
PPRE_IO_DATA pPreIoData = NULL;
PPRE_SOCKET_DATA pPreHandleData = NULL;

while (TRUE)
{
if (GetQueuedCompletionStatus(hIocp, &dwTransCount,
reinterpret_cast<LPDWORD>(&pPreHandleData),
reinterpret_cast<LPOVERLAPPED*>(&pPreIoData), INFINITE))
{
if (0 == dwTransCount && IoQuit != pPreIoData->IoType)
{
cout<<"Client"<<inet_ntoa(pPreHandleData->ClientAddr.sin_addr)
<<":"<<ntohs(pPreHandleData->ClientAddr.sin_port)
<<" is closed"<<endl;
closesocket(pPreHandleData->hSocket);
EnterCriticalSection(&csProtection);
IoDataVector::iterator itIoDelete = find(gIoDataVec.begin(),
gIoDataVec.end(), pPreIoData);
gIoDataVec.erase(itIoDelete);

// 这个地方用vector不合理,删除成本太高,不如改用list
SocketDataVector::iterator itSockDel = find(gSockDataVec.begin(),
gSockDataVec.end(), pPreHandleData);
gSockDataVec.erase(itSockDel);
LeaveCriticalSection(&csProtection);
delete *itIoDelete;
delete *itSockDel;
continue;
}
switch(pPreIoData->IoType)
{
case IoTransFile: // 传送文件完成
cout<<"Client"<<inet_ntoa(pPreHandleData->ClientAddr.sin_addr)
<<":"<<ntohs(pPreHandleData->ClientAddr.sin_port)
<<"Transmit finished"<<endl;
CloseHandle(reinterpret_cast<HANDLE*>(pPreIoData->Buffer));
goto LRERECV;
case IoSend:
cout<<"Client"<<inet_ntoa(pPreHandleData->ClientAddr.sin_addr)
<<":"<<ntohs(pPreHandleData->ClientAddr.sin_port)
<<"send finished"<<endl;
// 处理结束后,重新发起WSARecv请求:
LRERECV:
pPreIoData->IoType = IoRecv;
pPreIoData->DataBuf.len = MAX_BUFFER_SIZE;
memset(&pPreIoData->oa, 0, sizeof(OVERLAPPED));
WSARecv(pPreHandleData->hSocket, &pPreIoData->DataBuf,
1, &dwRecv, &dwFlags,
reinterpret_cast<LPWSAOVERLAPPED>(pPreIoData), NULL);
break;
case IoRecv:
cout<<"Client:"<<inet_ntoa(pPreHandleData->ClientAddr.sin_addr)
<<":"<<ntohs(pPreHandleData->ClientAddr.sin_port)
<<"recv finished"<<endl;
pPreIoData->IoType = IoSend;
if (!TransFile(pPreIoData, pPreHandleData, dwTransCount))
{
memset(&pPreIoData->oa,0, sizeof(OVERLAPPED));
strcpy(pPreIoData->DataBuf.buf, "File transmit error!\\r\\n");
pPreIoData->DataBuf.len = strlen(pPreIoData->DataBuf.buf);
WSASend(pPreHandleData->hSocket, &pPreIoData->DataBuf, 1,
&dwRecv, dwFlags, reinterpret_cast<LPWSAOVERLAPPED>(pPreIoData), NULL);
}
break;
case IoQuit:
goto LQUIT;
default:
;
}
}
}
LQUIT:
return 0;
}
HANDLE hIocp = NULL;
SOCKET hListen = NULL;
BOOL WINAPI ShutdownHandler(DWORD dwCtrlType)
{
PRE_SOCKET_DATA PreSockData = {0};
PRE_IO_DATA PreIoData = {0};
PreIoData.IoType = IoQuit;
if (hIocp)
{
PostQueuedCompletionStatus(hIocp, 1,
reinterpret_cast<ULONG_PTR>(&PreSockData),
reinterpret_cast<LPOVERLAPPED>(&PreIoData));
cout<<"Shutdown at"<<TimeNow()<<endl<<"Wait for a moment please"<<endl;
for (int t = 0; t < 80; t++)
{
Sleep(PRE_DOT_TIMER);
cout<<".";
}
CloseHandle(hIocp);
}
int i = 0;
for (; i < gSockDataVec.size(); i++)
{
PPRE_SOCKET_DATA pSockData = gSockDataVec[i];
closesocket(pSockData->hSocket);
delete pSockData;
}
for (i= 0; i <gIoDataVec.size(); i++)
{
PPRE_IO_DATA pIoData = gIoDataVec[i];
delete pIoData;
}
DeleteCriticalSection(&csProtection);
if (hListen)
closesocket(hListen);
WSACleanup();
exit(0);
return TRUE;
}
LONG WINAPI MyExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
ShutdownHandler(0);
return EXCEPTION_EXECUTE_HANDLER;
}
USHORT DefPort = 8182;
int main(int argc, char* argv[])
{
if (argc == 2)
DefPort = atoi(argv[1]);
InitializeCriticalSection(&csProtection);
SetUnhandledExceptionFilter(MyExceptionFilter);
SetConsoleCtrlHandler(ShutdownHandler, TRUE); // process CTRL+C
hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
WSADATA data = {0};
WSAStartup(0x0202, &data);
hListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == hListen)
{
ShutdownHandler(0);
}

SOCKADDR_IN addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(DefPort);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(hListen, reinterpret_cast<PSOCKADDR>(&addr),
sizeof(addr)) == SOCKET_ERROR)
{
ShutdownHandler(0);
}
if (listen(hListen, 256) == SOCKET_ERROR)
ShutdownHandler(0);
SYSTEM_INFO si = {0};
GetSystemInfo(&si);
si.dwNumberOfProcessors<<= 1;
for (int i= 0; i < si.dwNumberOfProcessors; i++)
{
// CreateThread(NULL, NULL, ThreadProc, hIocp, NULL, NULL);
QueueUserWorkItem(ThreadProc, hIocp, WT_EXECUTELONGFUNCTION);
}
cout<<"Startup at"<<TimeNow()<<endl<<"Work on Port"<<DefPort<<endl
<<"Press CTRL+C to Shutdown"<<endl<<endl<<endl;

while(TRUE)
{
int namelen = sizeof(addr);
memset(&addr,0, sizeof(addr));
SOCKET hAccept = accept(hListen, reinterpret_cast<PSOCKADDR>(&addr), &namelen);
if (hAccept != INVALID_SOCKET)
{
cout<<"accept a client:"<<inet_ntoa(addr.sin_addr)<<":"<<ntohs(addr.sin_port)<<endl;
PPRE_SOCKET_DATA pPreHandleData = new PRE_SOCKET_DATA;
pPreHandleData->hSocket = hAccept;
memcpy(&pPreHandleData->ClientAddr, &addr, sizeof(addr));
CreateIoCompletionPort(reinterpret_cast<HANDLE>(hAccept),
hIocp, reinterpret_cast<DWORD> (pPreHandleData), 0);
PPRE_IO_DATA pPreIoData = new (nothrow) PRE_IO_DATA;
i[FS:PAGE]f (pPreIoData)
{
EnterCriticalSection(&csProtection);
gSockDataVec.push_back(pPreHandleData);
gIoDataVec.push_back(pPreIoData);
LeaveCriticalSection(&csProtection);
memset(pPreIoData, 0, sizeof(PRE_IO_DATA));
pPreIoData->IoType = IoRecv;
pPreIoData->DataBuf.len = MAX_BUFFER_SIZE;
pPreIoData->DataBuf.buf = pPreIoData->Buffer;
DWORD dwRecv = 0;
DWORD dwFlags = 0;
WSARecv(hAccept, &pPreIoData->DataBuf, 1,
&dwRecv, &dwFlags,
reinterpret_cast<WSAOVERLAPPED*> (pPreIoData),
NULL);
}
else
{
delete pPreHandleData;
closesocket(hAccept);
}
}
}
return 0;
}

客户端:
#include <WinSock.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
int main(int argc, char* argv[])
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
{
cout<<"WSAStartup error, exit\\n";
return -1;
}

SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8182);
addr.sin_addr.s_addr = inet_addr("192.168.4.121");
int ierr = connect(sock, (sockaddr*)&addr, sizeof(addr));
if (ierr != 0)
return -1;

char szBuff[2000] = {0};
char *s = "c:\\\\1.txt";
ierr = send(sock, s, strlen(s)+1, 0);
if (ierr != (strlen(s)+1))
return -1;

int iLen = recv(sock, szBuff, 1024, 0);
if (iLen > 0)
{
for (int i = 0; i < iLen; i++)
cout<<szBuff[i];
}
else
cout<<"recv() error"<<endl;
return 0;
}
(iwgh)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/200708/6771.html]
本文出处:网络博客 作者:iwgh
顶一下
(0)
0%
踩一下
(1)
100%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容