近期,在做网络通信时,需要开发出一个应用程序来随时更改转发的目标地址,并同时要一直接收别的主机发来的命令从而进行一系列操作。由于之前没有做过windows系统下的窗口程序开发,我开始一点一点学习怎么创建窗口,当应用界面大概成功的时候,出现了一个问题。就是我需要不断地去询问要不要改地址,有没有接收到新的命令。然而当我觉得只要把两个功能放在同一个循环中就可以实现时,却发现,两种功能有种互斥的感觉。当接收消息时,窗口界面的消息便获取不到,无法更改目标地址,我想着获取消息的功能里也没有写循环,怎么就一直出不来了呢?甚至想着将接收功能设置为守护进程,从而实现并发的效果,奈何之前一直在学习Linux系统,转过来发现Windows系统的进程创建要麻烦很多,又实在不理解为什么逻辑感觉没问题,会一直卡在那。我继续寻找问题所在,最后终于发现是因为接收函数处于阻塞状态,就是接不到消息我就一直在那接收,导致程序进行不下去。找到问题了,开始尝试解决,找到recv或recvfrom函数,这两个函数都是接收函数,看一下函数原型:
recv(SOCKET s,char *buf,int len,int flags);
recvfrom(SOCKET s,char *buf,int len,int flags,struct sockaddr *from,int *fromlen);
当recvfrom函数的后两个参数为NULL时也就和recv一样啦。解释一下各个参数:
s:套接字描述符;
buf:接收数据的缓冲区;
len:接收多长的数据;
flags:操作方式标志;(该问题主要出在这里,所以详细说一下)
一般设置为0:默认阻塞状态;(我这种情况就不一般,不能为0)
MSG_DONTWAIT:本次操作设置为不阻塞;(正常把flags参数改为这项就可以了,但它还是不一般,后面详聊)
MSG_PEEK:只用于接收函数,表示接收消息后在消息队列中保留原数据,不刷新缓冲区,只是从缓冲区查数据而不是取走数据;
MSG_WAITALL:要求阻塞操作;
还有很多其他标志,可以自行搜索,这里不再过多赘述;
后面两个参数只存在在recvfrom中,一般用来回传信息,表示已经接收到数据,增强数据传递的可靠性:
from:指向源地址缓冲区;
fromlen:指向源地址缓冲区长度;
将recvfrom函数的第四个参数由0改为MSG_DONTWAIT设置成非阻塞状态,继续测试发现找不到声明;
找不到声明,那就到头文件里看一下是不是写错了导致找不到宏定义,进入winsock2.h文件中查看发现,还真就没有这个定义;
后来查询资料发现,Linux系统里定义了很多宏来方便调用,但windows却没有,不要着急,不用急着将两个系统融合,还可以对套接字进行非阻塞设置;
找到windows系统的套接字设置函数ioctlsocket,也封装在winsock2.h头文件中,函数原型如下:
ioctlsocket(SOCKET s,__LONG32 cmd,u_long *argp);
s:套接字描述符;
cmd:对套接口s的操作命令;
argp:指向cmd所带参数的指针;
其中cmd也是包含很多命令,在这里我们用到FIONBIO,它表示支持或禁止套接口的非阻塞模式;
当cmd为FIONBIO时,argp为0表示阻塞状态,argp为1表示非阻塞状态;
所以,我们这里在套接字创建后对其进行设置:文章来源:https://www.toymoban.com/news/detail-498164.html
编译通过,问题解决,特此记录!文章来源地址https://www.toymoban.com/news/detail-498164.html
到了这里,关于关于recv、recvfrom的阻塞所遇到的问题(MSG_DONTWAIT)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!