🔥博客主页: 我要成为C++领域大神
🎥系列专栏:【C++核心编程】 【计算机网络】 【Linux编程】 【操作系统】
❤️感谢大家点赞👍收藏⭐评论✍️
本博客致力于分享知识,欢迎大家共同学习和交流。
网络编程中有两种模式:阻塞和非阻塞,默认是采用阻塞方式。
什么是阻塞和非阻塞
阻塞和非阻塞是对操作请求者在等待返回结果时的状态描述,阻塞时,在操作请求结果返回前,当前线程会被挂起,得到结果之后返回;非阻塞时,如果不能立刻得到结果,系统不会挂起当前线程,而是直接返回错误信息,因此对应非阻塞的情况,调用者需要定时轮询查看处理状态。
阻塞状态下,不占用CPU;非阻塞状态下,一直占用CPU。
举个例子:
老王烧水,把水壶放在炉子上,就在旁边等着水开---阻塞:不占用CPU,第一时间知道等待的事情发生了
老王烧水,把水壶放在炉子上,就去客厅看电视了,每隔一段时间回来看看水开了没---非阻塞:一直占用CPU,等待事情发生的时候并不能第一时间知道
在我们前面编写的UDP通信中,SOCKET默认是阻塞,ioctlsock函数可以设置为非阻塞
从官方帮助文档可以看出,第三个参数非0时,可以设置状态为非阻塞。
int WSAAPI ioctlsocket(
[in] SOCKET s,
[in] long cmd,
[in, out] u_long *argp
);
//-------------------------
// Set the socket I/O mode: In this case FIONBIO
// enables or disables the blocking mode for the
// socket based on the numerical value of iMode.
// If iMode = 0, blocking is enabled;
// If iMode != 0, non-blocking mode is enabled.
//socket默认是阻塞的,设置socket为非阻塞模式
u_long iMode=FIONBIO;
ioctlsocket(sock, FIONBIO, &iMode);
当将socket设置为非阻塞后,程序不会卡在recvfrom了,函数会立即返回,并返回10035(调用失败)错误代码。
缓冲区(buffer)
缓冲区是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。
创建socket时,在内核空间创建发送缓冲区和接收缓冲区
调用recvfrom函数的时候是从接收缓冲区中把数据拷贝到应用程序的空间
调用sendto函数的时候就是把数据拷贝到发送缓冲区中
int nRecvSize = 0;
int nSendSize = 0;
int size = sizeof(nRecvSize);
getsockopt(sock,SOL_SOCKET,SO_RCVBUF,(char*)&nRecvSize,&size);
getsockopt(sock,SOL_SOCKET,SO_SNDBUF,(char*)&nSendSize,&size);
cout << "nRecvSize:" << nRecvSize << " nSendSize:" << nSendSize << endl;
//65536字节 操作系统分配的接收和发送缓冲区大小为64k
发送的阻塞和非阻塞:
当发送缓冲区空间剩余不够大时,阻塞发送就是等待空间足够大以后,再往发送缓冲区中拷贝数据
当发送缓冲区空间剩余不够大时,非阻塞发送就是有多少空间就往里拷贝多少数据,剩余数据由应用程序自己处理