在 socket编程中,对于socket的读写默认都是阻塞的,但有的情况我们需要将其设置为非阻塞,比如做多路复用,或者通过select实现连接超时等功能,将socket设置为非阻塞,在windows和linux中的接口有所不同,在windows中使用ioctlsocket函数,在linux中使用 fcntl函数,下面我们做一个跨平台设置阻塞的函数SetBlock。
bool SetBlock(int sock,bool isblock)
{
int re = 0;
//通过宏区分windows和linux,如果是windows64位程序判断 _WIN64宏
#ifdef WIN32
unsigned long ul = 0;
if(!isblock) ul = 1;
re = ioctlsocket(sock, FIONBIO, (unsigned long*)&ul);
#else
//先取到现有描述符属性,保证本次更改不变动原有属性
int flags = fcntl(sock, F_GETFL, 0);
if (flags < 0) {
return false;
}
if(isblock)
{
flags = flags & ~O_NONBLOCK;
}
else
{
flags = flags | O_NONBLOCK;
}
re = fcntl(sock, F_SETFL, flags);
#endif
if (re != 0) return false;
return true;
}
//设置非阻塞
static void setnonblocking(int sockfd) {
unsigned long on = 1; //此值为0,会将套接字设置为阻塞(默认的);为1设置为非阻塞
if (0 != ioctlsocket(sockfd, FIONBIO, &on))
{
/* Handle failure. */
}
}
ioctlsocket
函数使用方法
ioctlsocket
函数是用于控制一个套接字的 I/O 操作的函数,该函数是在 Windows 系统下使用的。它的原型如下:
cCopy codeint ioctlsocket(
SOCKET s,
long cmd,
u_long *argp
);
其中,s
是要控制的套接字,cmd
是要执行的操作,argp
是传递给操作的参数。ioctlsocket
函数返回操作的结果,如果返回值为 SOCKET_ERROR
,则说明操作失败。
ioctlsocket
函数可以用来执行各种操作,比如:
- 获取套接字的当前状态(
FIONREAD
、FIONBIO
) - 设置套接字的非阻塞模式(
FIONBIO
) - 设置套接字的缓冲区大小(
SO_RCVBUF
、SO_SNDBUF
) - 获取套接字的错误状态(
SIO_GET_ERROR
) - 禁止或启用 Nagle 算法(
TCP_NODELAY
)
下面是一些使用 ioctlsocket
函数的示例代码:
cCopy code// 获取套接字接收缓冲区中可读取的字节数
u_long bytesAvailable;
ioctlsocket(socket, FIONREAD, &bytesAvailable);
// 设置套接字为非阻塞模式
u_long nonBlocking = 1;
ioctlsocket(socket, FIONBIO, &nonBlocking);
// 设置套接字的接收缓冲区大小为 1024 字节
int bufferSize = 1024;
setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (const char*)&bufferSize, sizeof(bufferSize));
// 获取套接字的错误状态
u_long socketError;
ioctlsocket(socket, SIO_GET_ERROR, &socketError);
// 禁用 Nagle 算法
u_long nagleOff = 1;
setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&nagleOff, sizeof(nagleOff));
需要注意的是,ioctlsocket
函数的使用方法和参数取值会因具体操作而有所不同,具体操作和参数请参考相关的文档或 API 参考手册。