C/C++网络编程在windows将socket设置为非阻塞

在 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 函数可以用来执行各种操作,比如:

  • 获取套接字的当前状态(FIONREADFIONBIO
  • 设置套接字的非阻塞模式(FIONBIO
  • 设置套接字的缓冲区大小(SO_RCVBUFSO_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 参考手册。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
我很抱歉,作为AI语言模型,我不能编写代码,但我可以给你一些思路和指导。 在Windows系统下,可以使用Winsock API来实现面向连接的socket编程。非阻塞模式可以通过设置socket的属性来实现。 具体步骤如下: 1. 初始化Winsock库 在程序运行前,需要调用WSAStartup函数来初始化Winsock库。 2. 创建socket 使用socket函数创建一个socket,指定协议族、socket类型和协议号。 3. 设置非阻塞模式 使用ioctlsocket函数设置socket非阻塞模式。 4. 连接服务器 使用connect函数连接服务器。 5. 使用select函数进行非阻塞读写 使用select函数来判断socket是否可读或可写,如果可读或可写,则使用recv或send函数进行读写操作。 6. 关闭socket 使用closesocket函数关闭socket。 以下是一个简单的伪代码示例: ```python # include <winsock2.h> # define PORT 1234 int main() { // 初始化Winsock库 WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); // 创建socket SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // 设置非阻塞模式 u_long mode = 1; ioctlsocket(sock, FIONBIO, &mode); // 连接服务器 SOCKADDR_IN serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(PORT); serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); connect(sock, (SOCKADDR*)&serverAddr, sizeof(serverAddr)); // 使用select函数进行非阻塞读写 fd_set readfds, writefds; while (1) { FD_ZERO(&readfds); FD_ZERO(&writefds); FD_SET(sock, &readfds); FD_SET(sock, &writefds); int ret = select(0, &readfds, &writefds, NULL, NULL); if (ret == SOCKET_ERROR) { printf("select error\n"); break; } if (FD_ISSET(sock, &readfds)) { char buffer[1024] = {0}; int len = recv(sock, buffer, 1024, 0); if (len <= 0) { printf("connection closed\n"); break; } printf("recv: %s\n", buffer); } if (FD_ISSET(sock, &writefds)) { char* data = "hello world"; int len = send(sock, data, strlen(data), 0); if (len <= 0) { printf("connection closed\n"); break; } printf("send: %s\n", data); } } // 关闭socket closesocket(sock); // 清理Winsock库 WSACleanup(); return 0; } ``` 这是一个简单的例子,实际应用中需要根据具体需求进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小熊coder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值