Linux 下写c 程序清空缓冲区

本文详细介绍了C语言中标准输入输出的概念,并探讨了如何处理缓冲区中的回车键问题,提供了两种有效的方法来避免回车键引起的程序错误。
在讲空缓冲区之前我觉得有必要了解一下标准输入输出?
  • 标准输入(stdin)设备:键盘,对应标准输入函数为scanf
  • 标准输出(stdout)设备:屏幕,对应标准输出函数为printf
  • 以上两个函数都包含在头文件stdio里
当我们从键盘中输入数据时,输入的数据不会直接存到你所定义的变量中,而是存在缓冲区中,当按下回车键后,scanf()函数才会将数据从缓冲区中取走,遵循先输入的数据先取走的原则,这里可以把缓冲区看成一个先进先出的队列。然而就在这时,出现了一个问题,当我们输入的是非字符或字符串类型的数据时,是否清空缓冲区对我们编程序想要的结果到时没什么影响,但是当我们想要在程序中多次输入字符类型数据时,第一次输入数据时以回车键作为结束,回车键是没有被清除的,还依然保存在缓冲区中!这里写图片描述这里写图片描述
有图有真相,看吧,第一个图为源码,第二个图为程序执行结果,其中i,j为字符类型变量,j为整形变量,当依次输入i和k之后,系统是不会给你输入字符j的机会i的直接输出结果,幸好我在这里输出的是它们的ascll码值,才将它们的原形显示出来,不难看出,i和k我输的是a和4,显示的没毛病,但是我没来的及输入j程序就已经退出了,那它怎么能输出个10呢,10的ascll码是什么!对,就是回车键,因为在输入字符i值即a后,回车作为结束,标准输入函数将a取走存在i中,缓冲区中的回车键还存在,由于(回车键为字符常量,不是整型常量,所以标准输入函数并不会将回车键取出赋给k,而是暂停一下等待用户往缓冲区中输入整形常量)(上面括号纯属个人猜测,逻辑上感觉是对的,所以写出来,若有错误,欢迎指出,嘻嘻)当输入整型常量4后,按回车结束,标准输入函数将4取走存在k中,下一个j为字符型变量,所以不用你输入标准输入函数就自动将缓冲区中的回车键存在j中。所以j的ascll码值为回车键的ascll码值。

好了bb了这么多,说下这个咋解决吧!

在Windows下写C程序时,用fflush(stdin);通过刷新缓冲区就很轻易将缓冲区清空,在linux下使用这个函数是没有用的,为了解决这个问题,我试了好长时间竟没试出一个靠谱的方法,为了不让大家浪费时间,我还是将我的方法分享一下,该怎样清空缓冲区呢?
  • 方法一
    setbuf(stdin,NULL);
    这里写图片描述
    这个操作可以理解为将控制输入流的文件指针指向了缓冲区重新设置为空,当下次再输入数据时就缓冲区就又从输入流指针处开始存,字符或字符串变量就不会取到回车符了。这个方法我是不常用的,直觉总觉得不靠谱!这里写图片描述
    观察程序运行结果,当程序结束后,总会留下一个尾巴,即回车符,导致总是自动在终端执行处执行一个回车键,很难受!反正不完美!
    • 方法二
      先看图吧:这里写图片描述这里写图片描述
      好吧,既然这个讨厌的回车键总喜欢往缓冲区跑,就直接将它拒之门外,这样当取数据时,就不会担心回车键捣乱了!Ok,完美!从此,我养成了一个编程的习惯,在输入函数后面总喜欢跟一个while(‘\n’!=getchar());这样讨厌的回车键永远也别想进我的缓冲区了!
    • 那scanf(“%*[^\n]”);这个字符串扫描集看似也有这一功能,如何解释呢!它看起来也是不让回车键进入缓冲区呀!貌似也有2的功能,然而实践一下,我们会得到真相这里写图片描述这里写图片描述
      请相信你的眼睛,它并没有将,回车键当在缓冲区外!所以j的ascll码仍为10,即回车键。
      总算将这个问题弄清除了!真香,哈哈!
<think>好的,用户想了解如何在Linux下用C语言清空UDP的发送和接收缓冲区。首先,我得回忆一下UDP协议的特点。UDP是无连接的,所以每个数据包都是独立的,不像TCP有连接状态和复杂的缓冲区管理。不过,UDP套接字在内核中确实有发送和接收缓冲区,但可能不像TCP那样有明确的控制方法。 接下来,我需要确认如何操作这些缓冲区。对于发送缓冲区,通常可以通过设置套接字选项来调整其大小,但直接清空可能需要更底层的操作。可能的方法是将套接字设置为非阻塞模式,然后不断读取直到没有数据为止。不过对于发送缓冲区,可能无法直接清空,因为数据一旦发送出去就不在缓冲区了,而未发送的数据可能需要覆盖或丢弃。 然后,关于接收缓冲区,用户可能希望丢弃所有待处理的数据。这里可以使用recvfrom函数非阻塞地读取数据直到返回EAGAIN或EWOULDBLOCK错误。同样,设置非阻塞模式是必要的步骤。 还需要考虑套接字选项,比如SO_RCVBUF和SO_SNDBUF,调整缓冲区大小可能有助于控制缓冲区,但清空可能需要结合其他方法。另外,重新创建套接字可能是一个彻底的解决方案,但会影响当前连接状态,可能不是用户想要的。 还需要注意权限问题,确保程序有足够的权限执行这些操作。同时,错误处理也很重要,比如检查系统调用的返回值,处理可能的错误情况。 最后,总结这些步骤,提供示例代码可能对用户有帮助,但需要确保代码的正确性和安全性,比如正确设置非阻塞模式,正确处理返回值,避免无限循环等。</think>在 Linux 系统下清空 UDP 套接字的发送/接收缓冲区,可以通过以下步骤实现: --- ### 一、UDP 缓冲区特性说明 1. **UDP 无连接特性**:UDP 没有真正的"发送缓冲区",数据直接交给内核后立即发送 2. **接收缓冲区**:内核会缓存接收到的数据包,直到被应用程序读取 3. **发送缓冲区限制**:实际受 `SO_SNDBUF` 参数影响,但数据发送后不会保留 --- ### 二、清空接收缓冲区 #### 方法 1:非阻塞读取 ```c #include <fcntl.h> #include <errno.h> void clear_udp_recv_buffer(int sockfd) { char buffer[65535]; // UDP 最大报文长度 struct sockaddr_in src_addr; socklen_t addrlen = sizeof(src_addr); // 设置为非阻塞模式 int flags = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); // 循环读取直到缓冲区空 while(1) { ssize_t n = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&src_addr, &addrlen); if(n == -1) { if(errno == EAGAIN || errno == EWOULDBLOCK) break; // 处理其他错误 perror("recvfrom"); break; } } // 恢复阻塞模式(可选) fcntl(sockfd, F_SETFL, flags); } ``` #### 方法 2:调整缓冲区大小(强制清空) ```c int zero = 0; setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero)); // 注意:之后需要恢复原始缓冲区大小 ``` --- ### 三、处理发送缓冲区 UDP 没有真正意义上的发送缓冲区,但可以: 1. **覆盖未发送数据**:直接发送新数据会覆盖尚未发送的报文 2. **关闭重建套接字**: ```c close(sockfd); sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 需要重新绑定和设置参数 ``` --- ### 四、注意事项 1. **权限问题**:需要 root 权限才能调整缓冲区大小 2. **性能影响**:频繁清空缓冲区可能影响网络性能 3. **多线程安全**:操作期间需要处理并发访问问题 4. **内核版本差异**:不同内核版本可能有不同的缓冲区实现细节 --- ### 五、推荐做法 1. 对于接收缓冲区:使用非阻塞模式定期清空 2. 对于发送"缓冲区":通过协议设计实现数据覆盖控制 3. 关键场景建议:直接重建套接字是最彻底的清理方式 需要根据具体应用场景选择合适的方法,建议结合网络抓包工具(如 tcpdump)验证缓冲区操作效果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值