1.WSASocket介绍
SOCKET WSASocket (
int af,
int type,
int protocol,
LPWSAPROTOCOL_INFO lpProtocolInfo,
GROUP g,
DWORD dwFlags
);
af:只支持AF_INET;
type:新套接口的类型描述。SOCK_STREAM tcp,SOCK_DGRAM udp。
lpProtocolInfo:一个指向PROTOCOL_INFO结构的指针,该结构定义所创建套接口的特性。如果本参数非零,则前三个参数(af, type, protocol)被忽略。
dwFlags :套接口属性描述
2.重叠IO创建
重叠的数据结构(WSAOVERLAPPED),一次投递一个或多个 Winsock I/O 请求。
创建套接字重叠IO套接字
SOCKET s=WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
win上使用socket创建socket默认设置WSA_FLAG_OVERLAPPED标志
3.重叠IO使用
WSASend // sends data on a connected socket. 提供一个指向已填充的数据缓冲区的指针。
WSASendTo // sends data to a specific destination, using overlapped I/O where applicable.
WSARecv // receives data from a connected socket.
WSARecvFrom //receives data on a socket and stores the source address. 提供存放接收数据的缓冲区
WSAIoctl //allows for miscellaneous control of a socket. 还可以使用重叠I/O操作的延迟完成特性。
AcceptEx //accepts a new connection, returns the local and remote address, and receives the first block of data sent by the client application.
TrnasmitFile //transmits file data over a connected socket handle. uses the operating system's cache manager to retrieve the file data, and provides high-performance file data transfer over sockets.
这里面WS_IO_PENDING 是最常见的返回值,这是说明我们的重叠函数调用成功了,但是I/O操作还没有完成。
如果和一个WSAOVERLAPPED结构一起来调用这些函数,那么函数会立即完成并返回,无论套接字是否是阻塞模式。判断I/O请求是否成功的方法有两个,分别是:
1、等待 事件对象通知。
2、通过 完成例程。
SOCKET WSASocket (
int af,
int type,
int protocol,
LPWSAPROTOCOL_INFO lpProtocolInfo,
GROUP g,
DWORD dwFlags
);
af:只支持AF_INET;
type:新套接口的类型描述。SOCK_STREAM tcp,SOCK_DGRAM udp。
lpProtocolInfo:一个指向PROTOCOL_INFO结构的指针,该结构定义所创建套接口的特性。如果本参数非零,则前三个参数(af, type, protocol)被忽略。
dwFlags :套接口属性描述
2.重叠IO创建
重叠的数据结构(WSAOVERLAPPED),一次投递一个或多个 Winsock I/O 请求。
创建套接字重叠IO套接字
SOCKET s=WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
win上使用socket创建socket默认设置WSA_FLAG_OVERLAPPED标志
3.重叠IO使用
WSASend // sends data on a connected socket. 提供一个指向已填充的数据缓冲区的指针。
WSASendTo // sends data to a specific destination, using overlapped I/O where applicable.
WSARecv // receives data from a connected socket.
WSARecvFrom //receives data on a socket and stores the source address. 提供存放接收数据的缓冲区
WSAIoctl //allows for miscellaneous control of a socket. 还可以使用重叠I/O操作的延迟完成特性。
AcceptEx //accepts a new connection, returns the local and remote address, and receives the first block of data sent by the client application.
TrnasmitFile //transmits file data over a connected socket handle. uses the operating system's cache manager to retrieve the file data, and provides high-performance file data transfer over sockets.
这里面WS_IO_PENDING 是最常见的返回值,这是说明我们的重叠函数调用成功了,但是I/O操作还没有完成。
如果和一个WSAOVERLAPPED结构一起来调用这些函数,那么函数会立即完成并返回,无论套接字是否是阻塞模式。判断I/O请求是否成功的方法有两个,分别是:
1、等待 事件对象通知。
2、通过 完成例程。
4.实例
#include "stdafx.h"
#include <stdio.h>
#include <afx.h>
#include <winsock2.h>
#define DATA_BUFSIZE 1024
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{
SOCKET ListenSocket,AcceptSocket;
WSAOVERLAPPED AcceptOverlapped;
WSABUF DataBuf;
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2),&wsaData);
ListenSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//创建TCP套接字
SOCKADDR_IN ServerAddr;//分配端口及协议族并绑定
ServerAddr.sin_family=AF_INET;
ServerAddr.sin_addr.S_un.S_addr =htonl(INADDR_ANY);
ServerAddr.sin_port=htons(8888);
bind(ListenSocket,(LPSOCKADDR)&ServerAddr, sizeof(ServerAddr));//绑定套接字
listen(ListenSocket, 5);
SOCKADDR_IN ClientAddr;// 定义一个客户端得地址结构作为参数
int addr_length=sizeof(ClientAddr);
WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
DWORD dwEventTotal = 0,
dwRecvBytes = 0,
Flags = 0;
AcceptSocket = accept(ListenSocket,(SOCKADDR*)&ClientAddr, &addr_length);
LPCTSTR lpIP = inet_ntoa(ClientAddr.sin_addr);// IP
UINT nPort = ClientAddr.sin_port;// Port
//为接受的套接字创建一个WSAOVERLAPPED结构,并给这个结构分配一个事件对象句柄,同时将该事件对象句柄分配给一个事件数组,以便稍后WSAWaitForMultipleEvents函数使用
EventArray[dwEventTotal] = WSACreateEvent();
ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));
AcceptOverlapped.hEvent = EventArray[dwEventTotal];
char buffer[DATA_BUFSIZE];
ZeroMemory(buffer, DATA_BUFSIZE);
DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = buffer;
dwEventTotal ++;
if(WSARecv(AcceptSocket ,(WSABUF *)&DataBuf,1,&dwRecvBytes,&Flags,&AcceptOverlapped,NULL) == SOCKET_ERROR)
{
if(WSAGetLastError() != WSA_IO_PENDING)
{
closesocket(AcceptSocket);
WSACloseEvent(EventArray[dwEventTotal]);
}
}
while(1)
{
DWORD dwIndex;
dwIndex = WSAWaitForMultipleEvents(dwEventTotal, EventArray ,FALSE ,WSA_INFINITE,FALSE);
// 注意这里返回的Index并非是事件在数组里的Index,而是需要减去WSA_WAIT_EVENT_0
dwIndex = dwIndex - WSA_WAIT_EVENT_0;
WSAResetEvent(EventArray[dwIndex]);
if(WSARecv(AcceptSocket ,&DataBuf,1,&dwRecvBytes,&Flags,&AcceptOverlapped, NULL) == SOCKET_ERROR)
{
if(WSAGetLastError() != WSA_IO_PENDING)
{
closesocket(AcceptSocket);
WSACloseEvent(EventArray[dwEventTotal]);
}
TRACE("dwRecvBytes = %2d\n",dwRecvBytes);
}
}
return 0;
}