此篇文章继续记录winsocket的常用函数
1、套接字选项
选项影响套接字的操作。获取和设置调节自选项的函数分别是getsockopt()和setsockopt()。
(1)setsockopt()
int
WSAAPI
setsockopt(
_In_ SOCKET s,
_In_ int level,
_In_ int optname,
_In_reads_bytes_opt_(optlen) const char FAR * optval,
_In_ int optlen
);
参数s:指示套接字句柄;
参数level:指定此选项被定义在哪个级别,如SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP等;
参数optname:声明套接字选项的名称;
参数optval:指定一个缓冲区,存储所请求或定义的选项值;
参数optlen:指定参数optval所指的缓冲区的大小
如果函数成功,则返回0,否则返回SOCKET_ERROR。
OSI网络分层结构对应参数level的不同级别:
应用层:参数level设置为SOL_SOCKET,是对套接字自身的一些参数的配置;
传输层:协议为TCP、UDP,参数level设置为IPPROTO_TCP、IPPROTO_UDP;
网络层:参数level设置为IPPROTO_IP。
BOOL bReuseaddr = TRUE;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&bReuseaddr, sizeof(BOOL));
2. 如果要已经处于连接状态的soket在调用closesocket后强制关闭,不经历 TIME_WAIT的过程:
BOOL bDontLinger = FALSE;
setsockopt(s, SOL_SOCKET, SO_DONTLINGER, (const char*)&bDontLinger, sizeof(BOOL));
3.在send(),recv()过程中有时由于网络状况等原因,发收不能预期进行,而设置收发时限:
int nNetTimeout = 1000;//1秒
//发送时限
setsockopt(socket,SOL_S0CKET, SO_SNDTIMEO,(char *)&nNetTimeout, sizeof(int));
//接收时限
setsockopt(socket,SOL_S0CKET, SO_RCVTIMEO,(char *)&nNetTimeout, sizeof(int));
4.在send()的时候,返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节 (异步);系统默认的状态发送和接收一次为8688字节(约为8.5K);
/ 接收缓冲区
int nRecvBuf = 32 * 1024;
//设置为32K
setsockopt(s, SOL_SOCKET, SO_RCVBUF, (const char*)&nRecvBuf, sizeof(int));
//发送缓冲区 int nSendBuf=32*1024;//设置为32K
setsockopt(s, SOL_SOCKET, SO_SNDBUF, (const char*)&nSendBuf, sizeof(int));
5. 如果在发送数据的时,希望不经历由系统缓冲区到socket缓冲区的拷贝而影响程序的性能:
int nZero = 0;
setsockopt(socket,SOL_S0CKET, SO_SNDBUF,(char *)&nZero, sizeof(nZero));
6.同上在recv()完成上述功能(默认情况是将socket缓冲区的内容拷贝到系统缓冲区):
int nZero = 0;
setsockopt(socket,SOL_S0CKET, SO_RCVBUF,(char *)&nZero, sizeof(int));
7.一般在发送UDP数据报的时候,希望该socket发送的数据具有广播特性:
BOOL bBroadcast=TRUE;
setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char*)&bBroadcast,sizeof(BOOL));
8.在client连接服务器过程中,如果处于非阻塞模式下的socket在connect()的过程中可以设置connect()延时,直到accpet()被呼叫(本函数设置只有在非阻塞的过程中有显著的作用,在阻塞的函数调用中作用不大)
BOOL bConditionalAccept = TRUE;
setsockopt(s, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, (const char*)&bConditionalAccept, sizeof(BOOL));
9.如果在发送数据的过程中(send()没有完成,还有数据没发送)而调用了closesocket(),以前我们一般采取的措施是"从容关闭"shutdown(s,SD_BOTH),但是数据是肯定丢失了,如何设置让程序满足具体应用的要求(即让没发完的数据发送出去后在关闭socket
struct linger
{
u_short l_onoff;
u_short l_linger;
};
linger m_sLinger;
m_sLinger.l_onoff = 1;//(在closesocket()调用,但是还有数据没发送完毕的时候容许逗留) 如果m_sLinger.l_onoff=0;则功能和2.)作用相同;
m_sLinger.l_linger = 5; //(容许逗留的时间为5秒)
setsockopt(s, SOL_SOCKET, SO_LINGER, (const char*)&m_sLinger, sizeof(linger));
(2)getsockopt()
int
WSAAPI
getsockopt(
_In_ SOCKET s,
_In_ int level,
_In_ int optname,
_Out_writes_bytes_(*optlen) char FAR * optval,
_Inout_ int FAR * optlen
);
此函数用于取得socket套接字的操作选项值,例:
int nNetTimeout;//时间
//发送时限
getsockopt(socket,SOL_S0CKET,SO_SNDTIMEO,(char *)&nNetTimeout,sizeof(int));
//函数会在nNetTimeout返回设置的时间
2、I/O控制命令
I/O控制命令(缩写为ioctl)用来控制套接字上I/O的行为,也可以用来获取套接字上未决的I/O信息。向套接字发送I/O控制命令的函数有两个:winsock1.1:ioctlsocket();winsock2:WSAIoctl()。
(1)ioctlsocket()
ioctlsocket()函数可以控制套接字的I/O模式
int
WSAAPI
ioctlsocket(
_In_ SOCKET s,
_In_ long cmd,
_Inout_ u_long FAR * argp
);
参数s:是一个套接字句柄
参数cmd:指示在套接字上要执行的命令
参数argp:指向套接字参数的指针
(2)WSAIoctl()
此函数是winsock2新引进的I/O控制命令函数,它增加了一些输入参数,同时还增加了一些输入参数用来从调用中返回数据。另外,该函数还可以使用重叠I/O。
int
WSAAPI
WSAIoctl(
_In_ SOCKET s,
_In_ DWORD dwIoControlCode,
_In_reads_bytes_opt_(cbInBuffer) LPVOID lpvInBuffer,
_In_ DWORD cbInBuffer,
_Out_writes_bytes_to_opt_(cbOutBuffer, *lpcbBytesReturned) LPVOID lpvOutBuffer,
_In_ DWORD cbOutBuffer,
_Out_ LPDWORD lpcbBytesReturned,
_Inout_opt_ LPWSAOVERLAPPED lpOverlapped,
_In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
参数dwIoControlCode:描述将进行的操作控制代码,在设置接收全部选项时使用SIO_RCVALL
参数lpvInBuffer:指向输入缓冲区的地址
参数cbInBuffer:指向输入缓冲区的大小
参数lpvOutBuffer:指向输出缓冲区的地址
参数cbOutBuffer:指向输出缓冲区的大小
参数IpcbBytesReturned:是一个输出参数,返回输出实际字节数的地址
参数IpOverlapped:指向WSAOVERLAPPED的结构的地址
参数IpCompletionRoutine:指向操作结束后调用的例程指针
注:最后两个参数在重叠I/O时才会使用。
示例:
u_long mode = 0;
ioctlsocket(s, FIONBIO, &mode); //控制为阻塞方式
u_long mode = 1;
ioctlsocket(s, FIONBIO, &mode); //控制为非阻塞方式