获取socket对应的接收缓冲区中的可读数据量
生活随笔
收集整理的這篇文章主要介紹了
获取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; }注意事項:
TCP網絡編程的基本流程
Linux與C++11多線程編程(學習筆記)
Linux select函數用法和原理
socket的阻塞模式和非阻塞模式(send和recv函數在阻塞和非阻塞模式下的表現)
connect函數在阻塞和非阻塞模式下的行為
獲取socket對應的接收緩沖區中的可讀數據量
總結
以上是生活随笔為你收集整理的获取socket对应的接收缓冲区中的可读数据量的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用java实现新浪爬虫,代码完整剖析(仅
- 下一篇: 软件工程期末复习二