windows socket扩展函数
1、AcceptEx()
AcceptEx()用于异步接收连接,可以取得客户程序发送的第一块数据。
- BOOL AcceptEx(
- _In_ SOCKET sListenSocket, //监听套接字句柄
- _In_ SOCKET sAcceptSocket, //指定一个未被使用的套接字,在这个套接字上接收新的连接
- _In_ PVOID lpOutputBuffer, //指定一个缓冲区,用来取得在新连接上接收到的第一块数据、服务器的本地地址、客户端地址, 该参数必须指定
- _In_ DWORD dwReceiveDataLength, //lpOutputBuffer中数据缓冲区的大小,这一大小不包括服务器的本地地址的大小也不包括客户端的远程地址大小, 为0表示AcceptEx将不等待接收任何数据,而是尽快建立连接。
- _In_ DWORD dwLocalAddressLength, //lpOutputBuffer缓冲区中为本地地址预留的长度。必须比最大地址长度多16
- _In_ DWORD dwRemoteAddressLength,//lpOutputBuffer缓冲区中中为远程地址预留的长度。必须比最大地址长度多16
- _Out_ LPDWORD lpdwBytesReceived, //接收到数据的长度,这个参数只在同步完成时有效,如果函数返回ERROR_IO_PENDING并在迟些时候完成操作,那 么这个DWORD没有意义,这时你必须获得从完成通知机制中读取操作字节数
- _In_ LPOVERLAPPED lpOverlapped //用来处理本请求的OVERLAPPED结构,不能为NULL
- );
AcceptEx()成功完成后执行了三个操作:1、接受了新的连接;2、新连接的本地地址和远程地址都会返回;3、接收到了远程主机发来的第一块数据。
如果没有错误发生,AcceptEx函数成功完成并返回TRUE。
如果函数失败,AcceptEx返回FALSE。可以调用WSAGetLastError函数获得扩展的错误信息,如果WSAGetLastError返回ERROR_IO_PENDING,那么这次行动成功启动并仍在进行中。
如果提供了数据接收缓冲区(dwReceiveDataLength不为0),AcceptEx()投递的重叠操作直到接受到连接并且读到数据之后才会完成。可以使用getsockopt的SO_CONNECT_TIME选项来检查一个连接是否已经接受,如果它已被接受,你可以获得连接已经建立了多长时间(秒数),如果套接字未连接,getsockopt返回0xFFFFFFFF。应用程序通过检查重叠操作是否完成,并组合SO_CONNECT_TIME选项可以确定是否连接已建立了一段时间但没有收到任何数据,我们建议您通过关闭连接来终止这些连接,从而使AcceptEx()完成操作并返回一个错误状态。例如:
int seconds;
int bytes = sizeof(seconds);
int iResult = ;
iResult = getsockopt(s, SOL_SOCKET, SO_CONNECT_TIME, (char *)&seconds, (PINT)&bytes);
if (iResult != NO_ERROR)
{
printf("getsockopt(SO_CONNECT_TIME) failed with error: %u\n", WSAGetLastError());
}
else
{
if (seconds == 0xFFFFFFFF)
printf("Connection not established yet\n");
else
printf("Connection has been established %ld seconds\n", seconds);
}
较accept函数而言,程序使用AcceptEx可以更快连接到一个套接字。
AcceptEx()是一个Microsoft扩展函数,它是从Mswsock.lib库中导出的,为了能够直接调用它而不链接到Mswsock.lib库(因为直接链接到这个库的话会将程序绑定在MicrosoftWinsock提供者上),需要使用WSAIoctl()将AcceptEx()加载到内存。WSAIoctl()是ioctlsocket()的扩展,它可以使用重叠I/O,函数的第3个到第6个参数是输入和输出缓冲区,在这里传递AcceptEx()函数的指针。具体如下:
// 加载扩展函数AcceptEx
DWORD dwBytes;
GUID GuidAcceptEx = WSAID_ACCEPTEX;
LPFN_ACCEPTEX lpfnAcceptEx = NULL;
int iResult = WSAIoctl(ListenSocket,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidAcceptEx,
sizeof(GuidAcceptEx),
&lpfnAcceptEx,
sizeof(lpfnAcceptEx),
&dwBytes,
NULL,
NULL);
if (iResult == SOCKET_ERROR) {
printf("WSAIoctl failed with error: %u\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return ;
} ...... //调用AcceptEx
BOOL bRetVal = lpfnAcceptEx(ListenSocket,
AcceptSocket,
lpOutputBuf,
outBufLen - ((sizeof(sockaddr_in) + ) * ),
sizeof(sockaddr_in) + ,
sizeof(sockaddr_in) + ,
&dwBytes,
&olOverlap);
if (bRetVal == FALSE) {
printf(L"AcceptEx failed with error: %u\n", WSAGetLastError());
closesocket(AcceptSocket);
closesocket(ListenSocket);
WSACleanup();
return ;
}
2、GetAcceptExSockaddrs()
GetAcceptExSockaddrs()是专为AcceptEx()准备的,它粘贴从AcceptEx()获得的数据,将本地和远程地址传递到sockaddr结构。
local socket address, and remote socket address)。 在windows XP 及随后版本中,当 AcceptEx函数完成操
作并且SO_UPDATE_ACCEPT_CONTEXT选项在被接受的socket中被设置时, 与被接受socket相关的本地地址(local
address )可以使用getsockname函数获得,类似的,与被接受socket相关的远程端地址(the remote address)可
以使用getpeername函数获得。
DWORD dwBytes;
GUID GuidGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
LPFN_GETACCEPTEXSOCKADDRS lpfnGetAcceptExSockaddrs = NULL;
int Result = WSAIoctl(ListenSocket,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&GuidGetAcceptExSockaddrs,
sizeof(GuidGetAcceptExSockaddrs),
&lpfnGetAcceptExSockaddrs,
sizeof(lpfnGetAcceptExSockaddrs),
&dwBytes,
NULL,
NULL);
3、TransmitFile
BOOL PASCAL TransmitFile(
SOCKET hSocket, //连接套接字,不能是SOCK_DGRAM或SOCK_RAM类型
HANDLE hFile, //文件句柄,在CreateFile()打开文件的时候可以指定FILE_FLAG_SEQUENTIAL_SCAN标识来提高缓存性能
DWORD nNumberOfBytesToWrite, //要传输的字节,0为传输整个文件
DWORD nNumberOfBytesPerSend, //每次发送的数据块的大小,0为默认大小
LPOVERLAPPED lpOverlapped, //如果套接字是已重叠方式创建的,指定这个参数可以进行异步I/O和指定文件偏移量,默认情况下套接字是以重叠方式创建的?
LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, //指定在文件数据发送之前和之后要发送的数据
DWORD dwFlags //标志
); typedef void (*LPFN_TRANSMITFILE)(); 如果hFile设为NULL的话,lpTransmitBuffers将被传输。
lpOverlapped为NULL的话,传输会从当前文件指针开始,否则OVERLAPPED结构中的偏移量值将指定文件偏移值。
TransmitFile()一次只能发送2的32次方减1大小的文件(大约为2G),超过这个大小的话将nNumberOfBytesToWrite参数设为非0的合理值,多次调用TransmitFile()即可。
在客户操作系统中只有两个TransmitFile()请求会被同时处理,服务器版本的操作系统则没有这个最大并发限制,并且可以通过创建注册表项来设置这个最大并发值。
dwFlags可以为以下值的组合:
一般我们同时指定前两个标志,在这种情况下,当文件或缓冲区数据传输操作完成后套接字会断开,而传递给此函数的套接字可以被AcceptEx()或ConnectEx()重复使用,这样可以节省套接字创建的开销,因为套接字创建的开销很大。
如果hFile和lpTransmitBuffers都设为NULL的话(同时指定了前两个标志),函数不会发送任何数据,只是设置套接字允许重用。
TransmitFile 着重于服务器应用程序,因此只有在 Windows的服务器版本上,其功能才能得到完全发挥。对于家庭版或专业版,在任何时候,只可以有两个未完成的TransmitFile(或TransmitPackets)调用,如果超过这个数目,则多余的将排除等候,直到正在执行的调用结束之后,才会被处理。
SOCKET ConnectSocket = (SOCKET)lpParameter;
HANDLE hFile = CreateFileA("file.data",
GENERIC_READ,
,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
int iErrno = WSAGetLastError();
printf("createfile() error:%d\n", iErrno);
return -;
} /************************调用TransmitFile()发送一个文件,同步方式***********************/
BOOL bRet = FALSE;
bRet = TransmitFile(ConnectSocket, hFile, , , NULL/*&ov*/, NULL, TF_USE_DEFAULT_WORKER);
if (!bRet)
{
int iErrno = WSAGetLastError();
printf("TransmitFile() failed: %d\n", iErrno);
}
else
{
printf("transfer end\n");
} /************************调用TransmitFile()发送一个文件,异步方式***********************/
OVERLAPPED ov;
memset(&ov, , sizeof(ov));
ov.hEvent = WSACreateEvent();
BOOL bRet = TransmitFile(ConnectSocket, hFile, , , &ov, NULL, TF_USE_DEFAULT_WORKER);
if (!bRet)
{
int iErrno = WSAGetLastError();
if (iErrno == WSA_IO_PENDING || iErrno == ERROR_IO_PENDING)
{
DWORD flags;
DWORD sendBytes;
WSAGetOverlappedResult(ConnectSocket, &ov, &sendBytes, TRUE, &flags);
if (!ov.Internal)
{
printf("TransmitFile() sucess, send %d bytes\n", sendBytes);
}
else
{
printf("TransmitFile() failed: %d\n", WSAGetLastError());
}
}
else
{
printf("TransmitFile() failed immediately: %d\n", iErrno);
}
} //关闭建立连接的套接字
closesocket(ConnectSocket);
CloseHandle(hFile);
4、TransmitPackets()
TransmitPackets()与TransmitFile()功能类似,不同的是它可以发送多个文件或多个内存缓冲区中的数据。
BOOL PASCAL TransmitPackets(
SOCKET hSocket, //连接套接字,可以是SOCK_DGRAM
LPTRANSMIT_PACKETS_ELEMENT lpPacketArray, //封包元素数组
DWORD nElementCount, //lpPacketArray中封包元素的的数量
DWORD nSendSize, //每次发送数据的大小
LPOVERLAPPED lpOverlapped, //同TransmitFile()
DWORD dwFlags //同TransmitFile,不过不是以TF开头而是以TP开头
);
typedef void (*LPFN_TRANSMITPACKETS)();
lpPacketArray封包元素数组是LPTRANSMIT_PACKETS_ELEMENT结构类型的数组:
typedef struct _TRANSMIT_PACKETS_ELEMENT {
ULONG dwElFlags; //指定此元素中包含的缓冲区类型:文件TP_ELEMENT_FILE或内存TP_ELEMENT_MEMORY或TP_ELEMENT_EOP
ULONG cLength; //指定要传输文件的多少个字节,0为传输整个文件
union {
struct {
LARGE_INTEGER nFileOffset;//文件的偏移量,-1表示从当前文件指针传输
HANDLE hFile;//文件句柄
};
PVOID pBuffer;//数据内存缓冲区
};
} TRANSMIT_PACKETS_ELEMENT;
dwElFlags成员的TP_ELEMENT_EOP标志可以和另外两个标志按位或组合,指示在发送中这个元素不应该和后面的元素混合起来,这是用来精确的控制面向数据报或消息的socket传输。
使用TransmitFile()和TransmitPackets()的除了可以提高发送文件的效率外的另一个好处就是可以通过指定TF_REUSE_SOCKET和TF_DISCONNECT标志来重用套接字句柄。每当API完成数据的传输工作后,就会在传输层级别断开连接,这样这个套接字就又可以重新提供给AcceptEx()使用。采用这种优化的方法编程,将减轻那个专门做接受操作的线程创建套接字的压力
5、ConnectEx() ConnectEx()用来异步连接调用,连接建立之后也可以发送数据。由于ConnectEx使用的是异步通知机制,所以如果我们的客户端程序需要多个连接的话使用ConnectEx就不用为每个连接使用一个线程来管理这个连接了。
BOOL PASCAL ConnectEx(
_In_ SOCKET s, //未连接的socket
_In_ const struct sockaddr *name, //要连接的远程地址
_In_ int namelen, //远程地址长度
_In_opt_ PVOID lpSendBuffer, //建立连接后要发送的数据,NULL为不发送
_In_ DWORD dwSendDataLength, //lpSendBuffer中数据长度
_Out_ LPDWORD lpdwBytesSent, //实际发送的字节数
_In_ LPOVERLAPPED lpOverlapped //重叠结构,必须指定);
连接可能不会立即成功,这时ConnectEx()返回FALSE,调用WSAGetLastError()返回ERROR_IO_PENDING表明连接正在进行。如果错误码是 WSAECONNREFUSED, WSAENETUNREACH, 或 WSAETIMEDOUT那么可以再次调用ConnectEx进行连接。
当连接成功或失败后lpOverlapped指向的重叠结构会得到通知,可以使用事件或完成端口作为完成通知机制。GetQueuedCompletionStatus or GetOverlappedResult or WSAGetOverlappedResult函数的lpNumberOfBytesTransferred参数可以获得发送的字节数。
6、DisConnectEx()
DisConnectEx()支持异步关闭套接字上的连接,并允许重用套接字。
BOOL DisconnectEx(
_In_ SOCKET hSocket, //面向连接的套接字
_In_ LPOVERLAPPED lpOverlapped, //如果套接字是以重叠方式创建的,指定这个参数以进行重叠I/O操作
_In_ DWORD dwFlags, //TF_REUSE_SOCKET或0,0为仅仅断开连接,TF_REUSE_SOCKET为可重用套接字
_In_ DWORD reserved //保留 );
如果这个函数接受了一个重叠结构,并且在要关闭的套接字上仍有未决操作,它会返回FALSE,出错代码是WSA_IP_PENDING,一旦套接字上的所有未决操作都返回,DisConnectEx()投递的操作就会完成。
如果以阻塞方式调用这个函数的话,它将在所有未决I/O都完成后才返回。
windows socket扩展函数的更多相关文章
- 高性能 Windows Socket 组件 HP-Socket v3.0.2 正式发布
HP-Socket 是一套通用的高性能 Windows Socket 组件包,包含服务端组件(IOCP 模型)和客户端组件(Event Select 模型),广泛适用于 Windows 平台的 TCP ...
- 高性能 Windows Socket 组件 HP-Socket v3.0.1 正式发布
HP-Socket 是一套通用的高性能 Windows Socket 组件包,包含服务端组件(IOCP 模型)和客户端组件(Event Select 模型),广泛适用于 Windows 平台的 TCP ...
- 高性能 Windows Socket 组件 HP-Socket v2.3.1-beta-2 发布
HP-Socket 是一套通用的高性能 Windows Socket 组件包,包含服务端组件(IOCP 模型)和客户端组件(Event Select 模型),广泛适用于 Windows 平台的 TCP ...
- 高性能 Windows Socket 组件 HP-Socket v2.3.1-beta-1 发布
HP-Socket 是一套通用的高性能 Windows Socket 组件包,包含服务端组件(IOCP 模型)和客户端组件(Event Select 模型),广泛适用于 Windows 平台的 TCP ...
- 高性能 Windows Socket 组件 HP-Socket v2.2.3 正式发布
HP-Socket 是一套通用的高性能 Windows Socket 组件包,包含服务端组件(IOCP 模型)和客户端组件(Event Select 模型),广泛适用于 Windows 平台的 TCP ...
- 通用高性能 Windows Socket 组件 HP-Socket v2.2.2 正式发布
HP-Socket 是一套通用的高性能 Windows Socket 组件包,包含服务端组件(IOCP 模型)和客户端组件(Event Select 模型),广泛适用于 Windows 平台的 TCP ...
- linux tcp/ip编程和windows tcp/ip编程差别以及windows socket编程详解
最近要涉及对接现有应用visual c++开发的tcp客户端,花时间了解了下windows下tcp开发和linux的差别,从开发的角度而言,最大的差别是头文件(早期为了推广尽可能兼容,后面越来越扩展, ...
- 转:Windows Socket五种I/O模型
原文转自: Windows Socket五种I/O模型 Winsock 的I/O操作: 1. 两种I/O模式 阻塞模式:执行I/O操作完成前会一直进行等待,不会将控制权交给程序.套接字 默认为阻塞模 ...
- 【windows socket+TCPserverclient】
Windows Socket+TCPserverclient Winsock是 Windows下套接字标准. Socket套接字基于计算机网络,提供同一系统上不同进程或由局 ...
随机推荐
- Linux 下 mysql的基本配置
Linux 下 mysql的基本配置 2013年02月27日 ⁄ MySQL ⁄ 共 3000字 ⁄ 暂无评论 ⁄ 被围观 2,483 views+ 1. Linux mysql安装: $ yu ...
- Netty---入门程序,搭建Websocket 服务器
Netty 常用的场景: 1.充当HTTP 服务器,但Netty 并没有遵循servlet 的标准,反而实现了自己的一套标准进行Http 服务: 2,RPC 远程调用,在分布式系统中常用的框架 3.S ...
- mysql乐观锁总结和实践(一)
最近学习了一下数据库的悲观锁和乐观锁,根据自己的理解和网上参考资料总结如下: 悲观锁介绍(百科): 悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持 ...
- centos7下Redis3的安装与使用
redis是一个开源的,使用C语言编写的,支持网络交互的,可基于内存也可持久化的Key-Value数据库. 一.安装redis 下载redis源码 > wget http://download. ...
- python3.5.2中文字符乱码问题解决
>>> str = "世界你好!" >>> b = str.encode('utf-8') >>> type(b) <c ...
- Linux驱动之按键驱动编写(查询方式)
在Linux驱动之LED驱动编写已经详细介绍了一个驱动的编写过程,接着来写一个按键驱动程序,主要是在file_operations结构中添加了一个read函数.还是分以下几步说明 1.查看原理图,确定 ...
- Android开发之SharedPreferences的封装
对于大部分初学者来说,如果想利用SharedPreferences进行数据存储的话大部分人(包括本人)应该会这样: 存储: SharedPreferences sharedPreferences = ...
- PAT 1021 个位数统计 (15)(C++&Java&Python)
1021 个位数统计 (15)(15 分) 给定一个k位整数N = d~k-1~*10^k-1^ + ... + d~1~*10^1^ + d~0~ (0<=d~i~<=9, i=0,.. ...
- IntelliJ idea 的破解
·1.破解的jar包下载链接: https://pan.baidu.com/s/1JV6GwguGQNs5pNQtst29Hw 提取码: u2jd 2.安装和破解地址:https://www.cnb ...
- spec文件写作规范
spec文件写作规范 2008-09-28 11:52:17 分类: LINUX 1.The RPM system assumes five RPM directories BUILD:rpmbuil ...