您当前的位置: 主页网站优化软件知识

zz基于完成端口的办事器代码

发布于:2014-03-17 18:41:07  作者:兄弟网络   点击:

#include "stdio.h"
#include "stdlib.h"
#include "winsock2.h"
#include "mswsock.h"

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

/*
重叠IO有三种方法:
1. 一次投递分配一次IO,完成时释放
2. 为每个套接口绑定一个IO
3. 采用IO池,每次投递从池中取出一个IO,完成时放回
特点:
1. 当内存分配速度达到一定程度时,系统内存会呈线性增加
2. 一个套接口可能有多个投递操作
3. 在大型的办事器开发中,推荐该方法

多次IO投递分析:
1. 多次OP_READ,网站SEO,例如,连续投递三次OP_READ,当投递完成时,系统分别会把接收到的数据拷贝到OV的缓冲区中
2. 多次OP_WRITE,由于不知道成功发送了多少字节,所以必须保留数据到发送缓冲区,在操作完成之前,不能再投递发送操作了,
否则会造成数据发送混乱。
解决措施:
发送数据时,
int SendData(pSocket, szbuf, len)
{
EnterCriticalSection(&pSocket->cs);

memcpy(pSocket->gBufSend + pSocket->gLenSend, szbuf, len);
pSocket->gLenSend += len;

if (pSocket->nIOSend == 0)
{
WSASend(...);
pSocket->nIOSend ++;
}

LeaveCriticalSection(&pSocket->cs);
}

投递完成时,

case IO_WRITE:
{
EnterCriticalSection(&pSocket->cs);

memcpy(pSocket->gBufSend, pSocket->gBufSend + dwTrans, pSocket->gLenSend - dwTrans);
pSocket->gLenSend -= dwTrans;

if (pSocket->gLenSend > 0 && pSocket->nIOSend == 0)
{
WSASend(...);
pSocket->nIOSend ++;
}

LeaveCriticalSection(&pSocket->cs);

注意:坚决禁止在一个套接口上多次投递WRITE操作,使用SendData()方法可以保证始终只有一次WRITE操作
*/

///////////////////////////////////////////////////////////////////////////////
#define MAX_BUFF_SIZE 4096
#define MAX_PACK_SIZE 1024

//HANDLE结构,作为每个SOCKET的KEY,网站优化,保存每个SOCKET的用户缓冲区
struct PER_HANDLE_DATA
{
SOCKET s;
int nIOSend;
int nIORecv;

char gBufRecv[MAX_BUFF_SIZE];
int gLenRecv;

char gBufSend[MAX_BUFF_SIZE];
int gLenSend;
};
typedef struct PER_HANDLE_DATA PER_HANDLE_DATA_t;

//IO结构,向套接口投递操作时使用
struct PER_IO_DATA
{
OVERLAPPED ol;
SOCKET s;

char szBuf[MAX_PACK_SIZE*2];
DWORD dwBytes;
DWORD dwFlags;

int op;

#define OP_ACCEPT 1
#define OP_READ 2
#define OP_WRITE 3
#define OP_QUIT 4
};
typedef struct PER_IO_DATA PER_IO_DATA_t;

///////////////////////////////////////////////////////////////////////////////

//向侦听套接口投递ACCEPT操作
void PostAccept(SOCKET socks, PER_IO_DATA_t *pIO)
{
pIO->s = socket(AF_INET, SOCK_STREAM, 0);
pIO->op = OP_ACCEPT;

AcceptEx(socks, pIO->s, pIO->szBuf,
0,
sizeof(struct sockaddr) + 16,
sizeof(struct sockaddr) + 16,
&pIO->dwBytes,
&pIO->ol);
}

//向客户套接口投递RECV操作
void PostRecv(SOCKET sockc, PER_IO_DATA_t *pIO)
{
WSABUF wbuf;
wbuf.buf = pIO->szBuf;
wbuf.len = sizeof(pIO->szBuf);
pIO->op = OP_READ;

WSARecv(sockc, &wbuf, 1, &pIO->dwBytes, &pIO->dwFlags, &pIO->ol, NULL);
}

//向客户套接口投递Send操作
void PostSend(SOCKET sockc, PER_IO_DATA_t *pIO, char *szbuf, int nlen)
{
WSABUF wbuf;
wbuf.buf = szbuf;
wbuf.len = nlen;
pIO->op = OP_WRITE;

WSASend(sockc, &wbuf, 1, &pIO->dwBytes, pIO->dwFlags, &pIO->ol, NULL);
}

PER_IO_DATA_t *GetIO()
{
PER_IO_DATA_t *IO = new PER_IO_DATA_t;
memset(IO, 0, sizeof(PER_IO_DATA_t));
return IO;
}

void FreeIO(PER_IO_DATA_t *pIO)
{
delete pIO;
}

///////////////////////////////////////////////////////////////////////////////

void PostAccept(SOCKET socks, PER_IO_DATA_t *pIO);
void PostRecv(SOCKET sockc, PER_IO_DATA_t *pIO);

PER_IO_DATA_t *GetIO(); //模拟从IO池获取
void FreeIO(); //将IO放回IO池

int main()
{
HANDLE hIOCP = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if (hIOCP == NULL)
{
printf("CreateIoCompletionPort() failed!/n");
return -1;
}

WSADATA wsa;
WSAStartup(MAKEWORD(2,2), &wsa);

SOCKET socks = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(9988);

int ret = bind(socks, (struct sockaddr*)&sin, sizeof(sin));
if (ret == SOCKET_ERROR)
{
printf("bind() failed!/n");
return -1;
}

listen(socks, 5);

PER_HANDLE_DATA_t *Handle = new PER_HANDLE_DATA_t;
memset(Handle, 0, sizeof(PER_HANDLE_DATA_t));
Handle->s = socks;
::CreateIoCompletionPort((HANDLE)Handle->s, hIOCP, (DWORD)Handle, 0);

for (int i = 0; i < 1; i ++)
{
PostAccept(socks, GetIO());
}

while (TRUE)
{
PER_HANDLE_DATA_t *pHandle;
PER_IO_DATA_t *pIO;
DWORD dwBytes;
int ret =::GetQueuedCompletionStatus(hIOCP, &dwBytes,
(LPDWORD)&pHandle, (LPOVERLAPPED*)&pIO, INFINITE);

if (ret == 0)
{
printf("[%d] error/n", pHandle->s);
closesocket(pHandle->s);
delete pHandle;
FreeIO(pIO);

continue;
}

else if (dwBytes == 0 &&
(pIO->op == OP_READ || pIO->op == OP_WRITE) )
{
printf("[%d] 连接断开/n", pHandle->s);
closesocket(pHandle->s);
delete pHandle;
FreeIO(pIO);

continue;
}

switch (pIO->op)
{
case OP_ACCEPT:
{
printf("接受[%d]的连接/n", pIO->s);

PER_HANDLE_DATA_t *Handle = new PER_HANDLE_DATA_t;
memset(Handle, 0, sizeof(PER_HANDLE_DATA_t));
Handle->s = pIO->s;
::CreateIoCompletionPort((HANDLE)Handle->s, hIOCP, (DWORD)Handle, 0);
FreeIO(pIO);

PostRecv(Handle->s, GetIO());
Handle->nIORecv ++;
PostAccept(pHandle->s, GetIO());
}
break;

case OP_READ:
{
pHandle->nIORecv --;

memcpy(pHandle->gBufRecv + pHandle->gLenRecv,
pIO->szBuf, dwBytes); //将已接收到字节拷贝到全局接收缓存
pHandle->gLenRecv += dwBytes;
pHandle->gBufRecv[pHandle->gLenRecv] = 0;

FreeIO(pIO);

printf("[%d] %s/n", pHandle->s, pHandle->gBufRecv);
memcpy(pHandle->gBufSend, pHandle->gBufRecv, pHandle->gLenRecv);
pHandle->gLenSend += pHandle->gLenRecv;
pHandle->gLenRecv = 0;

if (pHandle->nIOSend == 0)
{
PostSend(pHandle->s, GetIO(), pHandle->gBufSend, pHandle->gLenSend);
pHandle->nIOSend ++;
}

PostRecv(pHandle->s, GetIO());
}
break;

case OP_WRITE:
{
pHandle->nIOSend --;

memcpy(pHandle->gBufSend, pHandle->gBufSend + dwBytes, pHandle->gLenSend - dwBytes);
pHandle->gLenSend -= dwBytes;

FreeIO(pIO);

if (pHandle->gLenSend > 0 &&
pHandle->nIOSend == 0)
{
PostSend(pHandle->s, GetIO(), pHandle->gBufSend, pHandle->gLenSend);
pHandle->nIOSend ++;
}
}
break;

case OP_QUIT:
{
}
break;
}
}

return 0;
}

本文关键词: 代码| 服务器| 基于| 完成| 端口|

[相关阅读]

我们介绍

  兄弟网络科技工作室,专业从事日照百度推广,日照百度优化,日照网站建设,日照网络公司,日照网站制作,日照网站优化,日照软件制作。如果您感觉我们不错请分享↓给更多的人

收缩