C++编程-socket编程中为何要使用循环来调用阻塞式recv

        你是否奇怪阻塞式接收recv这样的函数为什么要用一个for循环才能收全所有的内容?至少其中一种可能性是因为UNIX的信号处理机制。
        在我的编程理念中,UNIX下的信号是一个徒增麻烦的东西,这也许是非控制台的Windows程序中没有信号的原因。
        试想,如果你写了一个程序,无论是一个7*24的,还是一次性运行的,你通常期望它做完一段完整的工作后才被停下来,而不是在接收到一个也许你并不想要的信号直接就退出来。除非你在写一个初级的试验用的小程序,比如在写一个没有办法优雅关闭的死循环,不打算在正式的生产系统上使用,不需要完整的处理一个事务后结束,你可以慵懒的使用一下信号,其他情况下,最好把它屏蔽掉。
        当然,你可以在接收到信号后设置退出标志,然后优雅的退出,然而有时候你并不能确信这个信号是你有意发出,因此最好的办法是你屏蔽掉所有的信号,在需要关闭时,使用自己的命令去关闭程序。
        信号充当的是软件中断,向程序指示异步事件的发生。要处理信号,需要将信号处理器与一个特定的信号类型关联起来。在信号处理器返回后,程序会在主上下文中,从收到信号之前的地方继续执行。
        屏蔽掉一个信号,可以在捕捉到该信号后调用一个空函数,也可以在signal函数中设置SIG_IGN来屏蔽信号。然而仅仅屏蔽了它是不够的,因为特定的阻塞式系统调用(如recv、read、write、ioctl等在信号发生时会退出阻塞。一旦退出阻塞,会把errorno设置为EINTR。
        因此,正常情况下我们需要对阻塞式的recv进行循环调用。
        至于停止程序,我们可以自己写一个管理程序,与我们的程序间进行进程间通信,这样我们就可以优雅的停止我们的程序了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 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
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值