获取socket对应的接收缓冲区中的可读数据量

获取socket对应的接收缓冲区中的可读数据量

本文介绍如何获取当前socket对应的接收缓冲区的可读数据量

在Linux上可以使用ioctl函数

#include <sys/ioctl.h>int ioctl (int __fd, unsigned long int __request, ...)

来看一个例子:

#include <sys/types.h> 
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <iostream>
#include <string.h>
#include <vector>
#include <errno.h>//无效fd标记
#define INVALID_FD  -1int main(int argc, char* argv[])
{//创建一个侦听socketint listenfd = socket(AF_INET, SOCK_STREAM, 0);if (listenfd == INVALID_FD){std::cout << "create listen socket error." << std::endl;return -1;}//将侦听socket设置为非阻塞的int oldSocketFlag = fcntl(listenfd, F_GETFL, 0);int newSocketFlag = oldSocketFlag | O_NONBLOCK;if (fcntl(listenfd, F_SETFL,  newSocketFlag) == -1){close(listenfd);std::cout << "set listenfd to nonblock error." << std::endl;return -1;}//复用地址和端口号int on = 1;setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on));//初始化服务器地址struct sockaddr_in bindaddr;bindaddr.sin_family = AF_INET;bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);bindaddr.sin_port = htons(3000);if (bind(listenfd, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) == -1){std::cout << "bind listen socket error." << std::endl;close(listenfd);return -1;}//启动侦听if (listen(listenfd, SOMAXCONN) == -1){std::cout << "listen error." << std::endl;close(listenfd);return -1;}	std::vector<pollfd> fds;pollfd listen_fd_info;listen_fd_info.fd = listenfd;listen_fd_info.events = POLLIN;listen_fd_info.revents = 0;fds.push_back(listen_fd_info);//是否存在无效的fd标志bool exist_invalid_fd;int n;while (true){exist_invalid_fd = false;n = poll(&fds[0], fds.size(), 1000);if (n < 0){//被信号中断if (errno == EINTR)continue;//出错,退出break;}else if (n == 0){//超时,继续continue;}int size = fds.size();for (size_t i = 0; i < size; ++i){// 事件可读if (fds[i].revents & POLLIN){if (fds[i].fd == listenfd){//侦听socket,接受新连接struct sockaddr_in clientaddr;socklen_t clientaddrlen = sizeof(clientaddr);//接受客户端连接, 并加入到fds集合中int clientfd = accept(listenfd, (struct sockaddr *)&clientaddr, &clientaddrlen);if (clientfd != -1){//将客户端socket设置为非阻塞的int oldSocketFlag = fcntl(clientfd, F_GETFL, 0);int newSocketFlag = oldSocketFlag | O_NONBLOCK;if (fcntl(clientfd, F_SETFL,  newSocketFlag) == -1){close(clientfd);std::cout << "set clientfd to nonblock error." << std::endl;						} else{struct pollfd client_fd_info;client_fd_info.fd = clientfd;client_fd_info.events = POLLIN;client_fd_info.revents = 0;fds.push_back(client_fd_info);std::cout << "new client accepted, clientfd: " << clientfd << std::endl;}				}}else {//socket 可读时获取当前接收缓冲区中的字节数目ulong bytesToRecv = 0;if (ioctl(fds[i].fd, FIONREAD, &bytesToRecv) == 0){std::cout << "bytesToRecv: " << bytesToRecv << std::endl;}//普通clientfd,收取数据char buf[64] = { 0 };int m = recv(fds[i].fd, buf, 64, 0);if (m <= 0){if (errno != EINTR && errno != EWOULDBLOCK){//出错或对端关闭了连接,关闭对应的clientfd,并设置无效标志位	std::cout << "client disconnected, clientfd: " << fds[i].fd << std::endl;close(fds[i].fd);fds[i].fd = INVALID_FD;exist_invalid_fd = true;							}			}else{std::cout << "recv from client: " << buf << ", clientfd: " << fds[i].fd << std::endl;}}}else if (fds[i].revents & POLLERR){//TODO: 暂且不处理}}// end  outer-for-loopif (exist_invalid_fd){//统一清理无效的fdfor (std::vector<pollfd>::iterator iter = fds.begin(); iter != fds.end(); ){if (iter->fd == INVALID_FD)iter = fds.erase(iter);else++iter;}}	}// end  while-loop//关闭所有socketfor (std::vector<pollfd>::iterator iter = fds.begin(); iter != fds.end(); ++ iter)close(iter->fd);			return 0;
}

image-20210707172353351

注意事项:

  1. 对于以下代码,第三个参数bytesToRecv是一个输出参数,对于大多数其他函数意味着bytesToRecv可以不指定初始化值,因为函数调用成功后会为该变量设置值,但对于ioctl函数是个例外,必须将bytesToRecv初始化为0

TCP网络编程的基本流程

Linux与C++11多线程编程(学习笔记)

Linux select函数用法和原理

socket的阻塞模式和非阻塞模式(send和recv函数在阻塞和非阻塞模式下的表现)

connect函数在阻塞和非阻塞模式下的行为

获取socket对应的接收缓冲区中的可读数据量

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/408157.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASP.NET 2.0 Club Web Site Starter Kit 补丁

ASP.NET2.0 Club Web Site Starter Kit 具有一个很大的缺陷&#xff1a;不支持中文。这里给出两种解决方案供大家参考方法一&#xff1a;1&#xff09;由于大家大部分都是用SQL SERVER2005 EXPRESS开发的&#xff0c;所以在建立好Club需要的数据表后&#xff0c;将每一个表的v…

Linux epoll的用法

Linux epoll的用法 epollfd_create函数 #include <sys/epoll.h>int epoll_create (int __size)参数含义__size此参数从Linux 2.6.8后就不再使用了,但必须设置成大于零的值 返回值含义>0可用的epollfd-1调用失败 epollfd_ctl函数 有了epollfd,我们需要将要检测事件…

EVC4.0 PPC2003 Emulator 转中文版

1. 安装Windows Mobile 2003 Second Edition Emulator Images for Pocket PC - CHS.msi 2. 将C:\Program Files\Windows CE Tools\wce420\POCKET PC 2003\Emulation\emul.xml文件中的start "" "C:\Program Files\Common Files\Microsoft Shared\Windo…

第一个 Win32 窗口程序

第一个 Win32 窗口程序 程序骨架 int WinMain(){ // 设计窗口外观及交互响应&#xff0c;注册&#xff0c;申请专利RegisterClass(...) ;// 生产窗口 CreateWindow(...); // 展示窗口 ShowWindow(...); // 粉刷窗口 UpdateWindow(...);// 进入消息循环 while (GetMessage(...)…

在C#中利用DirectX实现声音播放

在c#中利用directx实现声音播放我感觉声音的播放比较简单。我们从播放声音开始。为什么我这么觉得&#xff1f;我也不知道。 这里是展示最简单的directx播放声音的例子,我尽量省略了无关的代码。最后的代码只有19行,够简单了吧&#xff1f; 准备工作&#xff1a; 1.安装了dire…

windows网络编程

windows网络编程 TCP编程 服务端 这里我们有几点需要注意: 使用WSAStartup初始化网络库,即将与socket函数相关dll文件加载到进程地址空间中退出时,使用WSACleanup()卸载相关dll文件与Linux使用close函数关闭socket不同,windows需要使用closesocket函数关闭socket WSAStart…

TCP服务器epoll的多种实现

TCP服务器epoll的多种实现 对于网络IO会涉及到两个系统对象 用户空间中进程或者线程操作系统内核 比如发生read操作时就会经历两个阶段 等待数据就绪将数据从内核缓冲区拷贝到用户缓冲区 由于各个阶段多有不同的情况,一组合么就产生了多种网络 IO 模型 阻塞IO 在Linux中…

软件的社交能力

两个人之间互不相识&#xff0c;则无法交往&#xff0c;两个系统之间相互不能识别&#xff0c;那么也就不可能相互通讯。但是人有一种社交能力&#xff0c;这种能力可以保证两个不相识的人&#xff0c;相互认识&#xff0c;开始交往。两个系统之间没有这种能力&#xff0c;所以…

设计模式实践

以前写程序不是太注意&#xff0c;将程序中的执行接口、容器接口和加载工具混合在一起设计。例如一个服务工厂&#xff0c;对于调用方来说&#xff0c;他是不关心你的容器机制&#xff0c;他关心的是执行接口&#xff0c;即他的结果。而对于服务的加载程序&#xff0c;他关心如…

侯捷面向对象高级编程(二)

侯捷面向对象高级编程(二) 转换函数 转换函数没有返回值,返回值就是double即函数名,不需要自己写因为转换函数一般不会改变其中内容,所以要加const限定 两条路都可以走,就回产生歧义,报错 explict禁止自动转换,于是4无法转转换为Fraction pointer-like cliasses ->作用之后…

拒绝了对对象 'sp_sdidebug'(数据库 'master',所有者 'dbo')的 EXECUTE 权限

在.net中调用时出现“拒绝了对对象 sp_sdidebug&#xff08;数据库 master&#xff0c;所有者 dbo&#xff09;的 EXECUTE 权限”的错误的解决办法。该问题是我在用指定的URL启动项目后&#xff0c;再“附加进程”后运行程序时出现的。该问题主要是.net2005的调试机制引起的&am…

ASP.NET MVC 音乐商店 - 6. 使用 DataAnnotations 进行模型验证

在前面的创建专辑与编辑专辑的表单中存在一个问题&#xff1a;我们没有进行任何验证。字段的内容可以不输入&#xff0c;或者在价格的字段中输入一些字符&#xff0c;在执行程序的时候&#xff0c;这些错误会导致数据库保存过程中出现错误&#xff0c;我们将会看到来自数据库的…

人生的12个经典领悟

1、父子二人经过五星级饭店门口&#xff0c;看到一辆十分豪华的进口轿车。儿子不屑地对他的父亲说&#xff1a;「坐这种车的人&#xff0c;肚子里一定没有学问&#xff01;」 父亲则轻描淡写地回答&#xff1a;「说这种话的人&#xff0c;口袋里一定没有钱&#xff01;」 2…