// OverlappedModel.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <afxsock.h>
//#include "winsock2.h"
//1.定义变量
#define DATA_BUFSIZE 4096 //接收缓冲区大小
SOCKET ListenSocket;//监听套接字
SOCKET AcceptSocket;//与客户端通信的套接字
WSAOVERLAPPED AcceptOverlapped;//重叠结构
WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];//用来通知重叠操作完成的事件句柄数组
WSABUF DataBuf[DATA_BUFSIZE];//用来接收WSASocket数据的缓冲区 (从系统的内核中获取WSASocket数据,可以设置len的大小来控制你想要获得len长度的数据)
DWORD dwEventTotal = 0;//程序中事件的总数
DWORD dwRecvBytes = 0;//接收到的字符长度
DWORD Flags = 0;//WSARecv的参数
int _tmain(int argc, _TCHAR* argv[])
{
//2.创建一个套接字,开始在指定的端口上监听连接请求
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);
ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//分配端口及协议族并绑定
SOCKADDR_IN ServerAddr;
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
ServerAddr.sin_port = htons(6000);
bind(ListenSocket,(LPSOCKADDR)&ServerAddr,sizeof(ServerAddr));//绑定套接字
listen(ListenSocket,5);//开始监听
//3.接受一个入站的请求
SOCKADDR_IN ClientAddr;//定义一个客户端的地址结构作为参数
int addr_length = sizeof(ClientAddr);
AcceptSocket = accept(ListenSocket,(sockaddr*)&ClientAddr,&addr_length);//与客户端通讯的socket
//4.建立并初始化重叠结构
//创建一个事件对象
EventArray[dwEventTotal] = WSACreateEvent();//返回值就是一个创建好的事件对象句柄
//ZeroMemory作用是用0来填充一块内存区域
ZeroMemory(&AcceptOverlapped,sizeof(WSAOVERLAPPED));//置零
AcceptOverlapped.hEvent = EventArray[dwEventTotal];//为重接结构关联事件
char buffer[DATA_BUFSIZE];
ZeroMemory(buffer, DATA_BUFSIZE);
DataBuf->len = DATA_BUFSIZE;//
DataBuf->buf = buffer;//初始化一个WSABUF结构
dwEventTotal++;
/*
int WSARecv(
SOCKET s, //投递这个操作的套接字
LPWSABUF lpBuffers, //接收缓冲区(一个指向WSABUF结构数组的指针。每一个WSABUF结构包含一个缓冲区的指针buf和缓冲区的长度len)
DWORD dwBufferCount, //数组中WSABUF结构的数量
LPDWORD lpNumberOfBytesRecvd,//如果接收操作立即完成,这里会返回函数调用所接收到的字节数指针
LPDWORD lpFlags, //一个指向标志位的指针(通常设置为0)
LPWSAOVERLAPPED lpOverlapped, //“绑定”的重叠结构(对于非重叠套接口则忽略)
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine//完成例程中会用到的参数,这里设为NULL
);
返回值:函数返回>0的值表示操作成功;
返回0表示连接中断,此时需要释放套接字资源;
返回SOCKET_ERROR(-1),表示出错,使用WSAGetLastError()获取出错的原因。
*/
//5.以WSAOVERLAPPED结构为参数,在套接字上投递WSARecv请求
//各变量已经初始化完毕,就可以开始Socket操作了,然后让
//WSAOVERLAPPED结构来替我们管理I/O请求,我们只用等待时间的触发就可以了
if (WSARecv(AcceptSocket,&DataBuf,1,&dwRecvBytes,&Flags,&AcceptOverlapped,NULL) == SOCKET_ERROR)
{
//返回WSA_IO_PENDING是正常情况,标识IO操作正在进行,不能立即完成
//如果不是,就关闭socket
if (WSAGetLastError() != WSA_IO_PENDING)
{
closesocket(AcceptSocket);
WSACloseEvent(EventArray[dwEventTotal]);
}
}
//为了持续接收客户端数据,重复6-10步
while (1)
{
/*
DWORD WSAWaitForMultipleEvents(
DWORD cEvents, //等候事件的总数量
const WSAEVENT* lphEvents,//事件数组的指针
BOOL fWaitAll, //如果设置为TRUE,则事件数组中所有事件被传信的时候函数才会返回
//FALSE,则任何一个事件被传信,函数都要返回。我们这里肯定是要设置为FALSE的
DWORD dwTimeout,//超时时间。如果超时,函数会返回WSA_WAIT_TIMEOUT
//如果设置为0,函数会立即返回
//如果设置为WSA_INFINITE只有在某一个事件被传信后才会返回
BOOL fAlertable//在完成例程中会用到这个参数,这里我们先设置为FALSE
);
*/
//6.用WSAWaitForMultipleEvents函数等待重叠操作返回的结果
//前面已经给WSARecv函数关联的重叠结构AcceptOverlapped赋了一个事件对象句柄,
//所以这里我们只需等待事件对象的触发即可。
//需要根据WSAWaitForMultipleEvents函数的返回值来确定事件数组中的 哪一个 事件被触发了
DWORD dwIndex;
//等候重叠I/O调用结束,因为我们把事件和Overlapped绑定在一起了(第4步的赋值即完成绑定),重叠操作完成后程序会接到事件通知
dwIndex = WSAWaitForMultipleEvents(dwEventTotal,EventArray,FALSE,WSA_INFINITE,FALSE);
//注意,这里的dwIndex并非是事件在数组里的Index,而是需要减去WSA_WAIT_EVENT_0
dwIndex = dwIndex - WSA_WAIT_EVENT_0;
/*
BOOL WSAAPI WSAResetEvent( WSAEVENT hEvent );
hEvent:标识一个开放的事件对象句柄。
*/
//7.使用WSAResetEvent函数重设当前这个用完的事件对象
//事件已经被触发之后,要将它重置一下留作下一次使用
WSAResetEvent(EventArray[dwIndex]);
/*
BOOL WSAGetOverlappedResult(
SOCKET s,//套接字句柄
LPWSAOVERLAPPED lpOverlapped,//这里是我们想要查询结果的那个重叠结构的指针
LPDWORD lpcbTransfer,//本次重叠操作的实际接收(或发送)的字节数
BOOL fWait,//确定函数是否等待重叠操作完成的标志。
//设置为TRUE时,直到操作完成函数才会返回;
//设置为FALSE时,而且操作仍处于挂起状态,那么函数就会返回FALSE
//错误为WSA_IO_INCOMPLETE
LPDWORD lpdwFlags//指向一个32位变量,该变量存放接收完成状态的附加标志位
);
*/
//8.使用WSAGetOverlappedResult函数获得重叠操做完成的通知
//这是我们最关心的:重叠操作究竟是什么结果,是否完成?而唯一需要我们做的就是对方的Socket连接是否已经关闭了
DWORD dwBytesTransferred;
WSAGetOverlappedResult(AcceptSocket,AcceptOverlapped,&dwBytesTransferred,FALSE,&Flags);
//如果参数3:dwBytesTransferred ==0,就表示未接收任何内容,表示对方连接已经关闭,我们也需要关闭
if (dwBytesTransferred == 0)
{
closesocket(AcceptSocket);
WSACloseEvent(EventArray[dwIndex]);//关闭事件
return;
}
//9.处理接收到的数据:WSABUF结构里就是我们WSARecv来的数据
//DataBuf->buf就是一个char*字符串指针
//...处理...
//10.在套接字上继续投递WSARecv请求
Flags = 0;
ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));
AcceptOverlapped.hEvent = EventArray[dwIndex];
DataBuf->len = DATA_BUFSIZE;
DataBuf->buf = buffer;
if (WSARecv(AcceptSocket,&DataBuf,1,&dwRecvBytes,&Flags,&AcceptOverlapped,NULL) ==SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
closesocket(AcceptSocket);
WSACloseEvent(EventArray[dwIndex]);
}
}
}
return 0;
}
以上!