AcceptEx Function 函数中文帮助

这个AcceptEx函数用来接收一个新的连接,返回本地和远程的sockaddr_in结构地址,并接收客户端应用程序返回的第一个数据块,
相当于AcceptEx在接受客户端的连接请求之后,如果客户端连接之后直接发送了数据,那么即可以接收到这第一数据块。

AcceptEx函数原型
BOOL AcceptEx(
  __in          SOCKET sListenSocket,
  __in          SOCKET sAcceptSocket,
  __in          PVOID lpOutputBuffer,
  __in          DWORD dwReceiveDataLength,
  __in          DWORD dwLocalAddressLength,
  __in          DWORD dwRemoteAddressLength,
  __out         LPDWORD lpdwBytesReceived,
  __in          LPOVERLAPPED lpOverlapped
);


 

sListenSocket
一个已经在监听状态下的socket句柄,用来等待客户端的连接

sAcceptSocket
一个已经创建好的socket句柄,用于客户端socket

lpOutputBuffer
一个指向buffer的指针,用来存储客户端发送来的第一组数据,还有本地和远程地址,
默认会写到指针指向的内存偏移为0的地方为起始地址,如果要保存本地或者远程的地址则这个参数必须被指定
注:如果要取得缓冲区的数据,那么大小应该是sizeof(lpOutputBuffer) - (sizeof(sockaddr_in)+16) * 2
也就是缓冲区的大小减去客户端和服务端的地址结构大小+16字节

dwReceiveDataLength
lpoutputbuffer缓冲区的大小,单位为字节数,并不用包括本地和远程地址的大小,如果此参数为0,那么AcceptEx将会
立即返回,不会等待接收到数据再返回。

dwLocalAddressLength
本地地址信息保留的字节数。该值必须至少16字节以上为使用传输协议的最大地址长度.

dwRemoteAddressLength
远程地址信息保留的字节数。该值必须至少16字节以上为使用传输协议的最大地址长度。不能为零。

lpdwBytesReceived
指向一个DWORD类型,用于接收完成后的字节数,如果投递的异步请求立即完成,则被成功更新,
如果返回ERROR_IO_PENDING并在之后完成,则这个参数的数值不确定

lpOverlapped
指向重叠结构的指针,用于处理请求。此参数必须被指定;它不能为空。

返回值
如果没有错误发生,那么AcceptEx在成功完成后返回true。
如果函数失败,那么会返回false,使用WSAGetLastError函数获取错误信息,如果WSAGetLastError函数返回ERROR_IO_PENDING
那么投递的异步操作将会在稍后完成,如果WSAGetLastError返回的错误是WSAECONNRESET,说明客户端的连接被关闭了。

注意事项
AcceptEx函数在成功调用后,执行三项任务
1、一个新的socket被接入
2、返回本地和远程的sockaddr_in结构
3、接收客户端发来的第一个数据块

注:在调用AcceptEx函数的时候,此函数是WSAIoctl函数传递SIO_GET_EXTENSION_FUNCTION_POINTER操作码,返回的一个函数指针,
WSAIoctl函数的输入缓冲区必须包含WSAID_ACCEPTEX,全局唯一标识符(GUID)的值标识调用扩展功能。成功返回,输出通过WSAIoctl函数包含一个指向AcceptEx函数。该wsaid_acceptex GUID是在mswsock h头文件定义。

可以使用 GetAcceptExSockaddrs 函数来获取本地和远程的地址以及客户端发送来的第一组数据,也可以使用getpeername函数来返回远程socket的地址,

AcceptEx其他
1、acceptex的sListenSocket必须是已经在监听的
2、acceptex的sAcceptSocket必须是已经创建好的,并且没有被使用也没有被连接的

当sAcceptSocket已经被系统接收以后,那么在工作者线程里通过GetQueuedCompletionStatus函数读取队列状态得到这个操作之后,
可以在这个sAcceptSocket套接字上使用WSASend WSARecv closesocket等操作

AcceptEx 示例代码

#include <stdio.h>
#include "winsock2.h"
#include "mswsock.h"

void main() {
  //----------------------------------------
  // Declare and initialize variables
  WSADATA wsaData;
  HANDLE hCompPort;
  LPFN_ACCEPTEX lpfnAcceptEx = NULL;
  GUID GuidAcceptEx = WSAID_ACCEPTEX;
  WSAOVERLAPPED olOverlap;
  
  SOCKET ListenSocket, AcceptSocket;
  sockaddr_in service;
  char lpOutputBuf[1024];
  int outBufLen = 1024;
  DWORD dwBytes;

  //----------------------------------------
  // Initialize Winsock
  int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
  if( iResult != NO_ERROR )
    printf("Error at WSAStartup\n");

  //----------------------------------------
  // Create a handle for the completion port
  hCompPort = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, (u_long)0, 0 );

  //----------------------------------------
  // Create a listening socket
  ListenSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
  if (ListenSocket == INVALID_SOCKET) {
    printf("Error at socket(): ListenSocket\n");
    WSACleanup();
    return;
  }

  //----------------------------------------
  // Associate the listening socket with the completion port
  CreateIoCompletionPort((HANDLE)ListenSocket, hCompPort, (u_long)0, 0);

  //----------------------------------------
  // Bind the listening socket to the local IP address
  // and port 27015
  hostent* thisHost;
  char* ip;
  u_short port;
  port = 27015;
  thisHost = gethostbyname("");
  ip = inet_ntoa (*(struct in_addr *)*thisHost->h_addr_list);

  service.sin_family = AF_INET;
  service.sin_addr.s_addr = inet_addr(ip);
  service.sin_port = htons(port);

  if ( bind( ListenSocket,(SOCKADDR*) &service, sizeof(service) )  == SOCKET_ERROR ) {
    printf("bind failed\n");
    closesocket(ListenSocket);
    return;
  }

  //----------------------------------------
  // Start listening on the listening socket
  if (listen( ListenSocket, 100 ) == SOCKET_ERROR) {
    printf("error listening\n");
  } 
  printf("Listening on address: %s:%d\n", ip, port);

  //----------------------------------------
  // Load the AcceptEx function into memory using WSAIoctl.
  // The WSAIoctl function is an extension of the ioctlsocket()
  // function that can use overlapped I/O. The function's 3rd
  // through 6th parameters are input and output buffers where
  // we pass the pointer to our AcceptEx function. This is used
  // so that we can call the AcceptEx function directly, rather
  // than refer to the Mswsock.lib library.
  WSAIoctl(ListenSocket, 
    SIO_GET_EXTENSION_FUNCTION_POINTER, 
    &GuidAcceptEx, 
    sizeof(GuidAcceptEx),
    &lpfnAcceptEx, 
    sizeof(lpfnAcceptEx), 
    &dwBytes, 
    NULL, 
    NULL);

  //----------------------------------------
  // Create an accepting socket
  AcceptSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (AcceptSocket == INVALID_SOCKET) {
    printf("Error creating accept socket.\n");
    WSACleanup();
    return;
  }

  //----------------------------------------
  // Empty our overlapped structure and accept connections.
  memset(&olOverlap, 0, sizeof(olOverlap));

  lpfnAcceptEx(ListenSocket, 
    AcceptSocket,
    lpOutputBuf, 
    outBufLen - ((sizeof(sockaddr_in) + 16) * 2),
    sizeof(sockaddr_in) + 16, 
    sizeof(sockaddr_in) + 16, 
    &dwBytes, 
    &olOverlap);

  //----------------------------------------
  // Associate the accept socket with the completion port
  CreateIoCompletionPort((HANDLE)AcceptSocket, hCompPort, (u_long)0, 0);

  //----------------------------------------
  // Continue on to use send, recv, TransmitFile(), etc.,.
  ...

}


 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值