select函數(一)

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

參數:

  • nfds:監控的文件描述符集里最大文件描述符加1,因為此參數會告訴內核檢測前多少個文件文件描述符
  • readfs:監控有讀數據到達文件描述符集合,傳入傳出參數
  • writefds:監控寫數據到達文件描述符集合,傳入傳出參數
  • exceptfds:監控異常發生到達文件描述符集合,如帶外數據到達異常,傳入傳出參數
  • timeout:定時阻塞監控時間。

?

#include <sys/select.h>                 
void FD_CLR(int fd, fd_set *set);     // 把文件描述符集里fd位清0
int  FD_ISSET(int fd, fd_set *set);   // 測試文件描述符集里fd是否置1
void FD_SET(int fd, fd_set *set);     // 把文件描述符集合里fd位置1
void FD_ZERO(fd_set *set);            // 把文件描述符集合里所有位清0

二、select函數用法圖解

三、實驗一

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>void perr_exit(const char *s)
{perror(s);exit(-1);
}int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{int n;again:if ((n = accept(fd, sa, salenptr)) < 0) {//ECONNABORTED 發生在重傳(一定次數)失敗后,強制關閉套接字//EINTR 進程被信號中斷if ((errno == ECONNABORTED) || (errno == EINTR)){goto again; }else{perr_exit("accept error");}}return n;
}int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{int n;if ((n = bind(fd, sa, salen)) < 0){perr_exit("bind error");}return n;
}int Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{int n;n = connect(fd, sa, salen);if (n < 0) {perr_exit("connect error");}return n;
}int Listen(int fd, int backlog)
{int n;if ((n = listen(fd, backlog)) < 0){perr_exit("listen error");}return n;
}int Socket(int family, int type, int protocol)
{int n;if ((n = socket(family, type, protocol)) < 0){perr_exit("socket error");}return n;
}ssize_t Read(int fd, void *ptr, size_t nbytes)
{ssize_t n;again:if ( (n = read(fd, ptr, nbytes)) == -1) {if (errno == EINTR)goto again;elsereturn -1;}return n;
}ssize_t Write(int fd, const void *ptr, size_t nbytes)
{ssize_t n;again:if ((n = write(fd, ptr, nbytes)) == -1) {if (errno == EINTR)goto again;elsereturn -1;}return n;
}int Close(int fd)
{int n;if ((n = close(fd)) == -1)perr_exit("close error");return n;
}

?

#ifndef __WRAP_H_
#define __WRAP_H_void perr_exit(const char *s);
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
int Bind(int fd, const struct sockaddr *sa, socklen_t salen);
int Connect(int fd, const struct sockaddr *sa, socklen_t salen);
int Listen(int fd, int backlog);
int Socket(int family, int type, int protocol);
ssize_t Read(int fd, void *ptr, size_t nbytes);
ssize_t Write(int fd, const void *ptr, size_t nbytes);
int Close(int fd);
ssize_t Readn(int fd, void *vptr, size_t n);
ssize_t Writen(int fd, const void *vptr, size_t n);
ssize_t my_read(int fd, char *ptr);
ssize_t Readline(int fd, void *vptr, size_t maxlen);#endif
  • 服務端server.c
//server.c
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/select.h>
#include "wrap.h"#define SERV_PROT 6666int main(int argc, char *argv[])
{int i, j, n, nread;int maxfd = 0;int listenfd, connfd;char buf[BUFSIZ];struct sockaddr_in clie_addr, serv_addr;socklen_t clie_addr_len;listenfd = Socket(AF_INET, SOCK_STREAM, 0);int opt = 1;setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));bzero(&serv_addr, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);serv_addr.sin_port = htons(SERV_PROT);Bind(listen, (struct sockaddr*)&serv_addr, sizeof(serv_addr));Listen(listenfd, 128);fd_set rset, allset;maxfd = listenfd;FD_ZERO(&allset);FD_SET(listenfd, &allset);while (1){rset = allset;nread = select(maxfd + 1, &rset, NULL, NULL, NULL);  //每次循環都從新設置select監控信號集if(nread < 0)perr_exit("select error");if (FD_ISSET(listenfd, &rset))   //說明有新的客戶端連接請求{clie_addr_len = sizeof(clie_addr);connfd = Accept(listenfd, (struct sockaddr *)&clie_addr, &clie_addr_len);FD_SET(connfd, &allset); //向監控文件描述符集合allset添加新的文件描述符connfdif (maxfd < connfd)maxfd = connfd;if (0 == --nread)  //說明select只返回一個,并且listenfd,后續執行無須執行continue;}for (i = listenfd + 1; i <= maxfd; i++){if (FD_ISSET(i, &rset)){if ((n = Read(i, buf, sizeof(buf))) == 0)  //當client關閉鏈接時, 服務端也關閉對應鏈接{Close(i);FD_CLR(i, &allset);  //解除select對此文件描述符的監控}else if(n == -1)perr_exit("read error");for (j = 0; j < n; ++j)buf[j] = toupper(buf[j]);Write(i, buf, n);}}}Close(listenfd);return 0;
}
  • 客戶端:clent.c
#include <arpa/inet.h>
#include "wrap.h"#define SERV_IP "192.168.245.139"
#define SERV_PORT 6666int main(void)
{int sfd, len;struct sockaddr_in serv_addr;char buf[BUFSIZ];sfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&serv_addr, sizeof(serv_addr));serv_addr.sin_family = AF_INET;inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);serv_addr.sin_port = htons(SERV_PORT);Connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));while (1) {fgets(buf, sizeof(buf), stdin);int r = Write(sfd, buf, strlen(buf));printf("Write r ======== %d\n", r);len = Read(sfd, buf, sizeof(buf));printf("Read len ========= %d\n", len);Write(STDOUT_FILENO, buf, len);}Close(sfd);return 0;
}
  • 公共頭文件集程序:wrap.h、wrap.c

輸出結果:

客戶端:

服務端:

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/385508.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/385508.shtml
英文地址,請注明出處:http://en.pswp.cn/news/385508.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Redis高級項目實戰,阿里P7級別面試經驗總結

第一次壓測 慘不忍睹&#xff0c;平均響應時間150ms&#xff0c;而且在這次壓測過程中還發現其它的問題&#xff0c;后臺報錯&#xff0c;經查是OpenSearch每秒查詢次數限制 優化代碼與配置 1、修改OpenSearch配置&#xff0c;并且將壓測環境中的OpenSearch連接地址改為內網地…

Makefile用法鏈接

Makefile的編寫及四個特殊符號的意義、$、$^、$ <font face"字體" size"字號" color"顏色">這里是需要突出顯示的內容</font> <font color#0099ff size12 face"黑體">黑體</font>

Redis高頻面試筆記:java版本號比較算法

1.三重心智模型 先給大家科普一個概念&#xff0c;“三重心智模型”。 認知科學家斯坦諾維奇&#xff0c;將人的心智模式&#xff0c;分成了三個部分。 第一層是自主心智&#xff0c;自主心智是我們通過進化與內隱學習獲得。比如&#xff0c;我們看到蛇就會害怕&#xff0c;情…

Redis高頻面試筆記:mysql8.0新特性

一、服務發布簡介 分布式系統架構下&#xff0c;服務發布是一件很麻煩的事情&#xff0c;特別是在構建自動發布流程和灰度測試的策略兩個核心方面。通常情況下如果不涉及數據層面的灰度流程&#xff0c;服務可以灰度上線&#xff0c;或者滾動上線&#xff0c;這兩種方式很常用…

Makefile (二)

一、line1的源碼 line1.h #ifndef _LINE_1_H #define _LINE_1_H void line1_print(const char *strMsg); #endifline1.cpp #include "line1.h" #include <stdio.h> void line1_print(const char *strMsg) {printf("This is line1 print %s.\r\n",st…

RocketMQ避坑指南:springcloud教程權威指南

1. Java 堆空間 **發生頻率&#xff1a;**5顆星 造成原因 無法在 Java 堆中分配對象 吞吐量增加 應用程序無意中保存了對象引用&#xff0c;對象無法被 GC 回收 應用程序過度使用 finalizer。finalizer 對象不能被 GC 立刻回收。finalizer 由結束隊列服務的守護線程調用&a…

IO多路復用之epoll

一、epoll函數族 1. 函數epoll_creat&#xff1a; 該函數生成一個epoll專用的文件描述符 #include <sys/epoll.h> int epoll_creae(int size); //epoll上能關注的最大描述符數 2. epoll_ctl&#xff1a;用于控制某個epoll文件描述符事件&#xff0c;可以注冊、修改、刪…

26. 刪除排序數組中的重復項

給定一個排序數組&#xff0c;你需要在原地刪除重復出現的元素&#xff0c;使得每個元素只出現一次&#xff0c;返回移除后數組的新長度。 不要使用額外的數組空間&#xff0c;你必須在原地修改輸入數組并在使用 O(1) 額外空間的條件下完成。 示例 1: 給定數組 nums [1,1,2], …

Leetcode 31. Pow(x, n) 解題報告

class Solution {public:double myPow(double x, int n) {double res 1.0;for(int i n; i ! 0; i / 2){if(i % 2 ! 0)res * x;x * x;}return n < 0 ? 1 / res : res;} };

572. 另一個樹的子樹

給定兩個非空二叉樹 s 和 t&#xff0c;檢驗 s 中是否包含和 t 具有相同結構和節點值的子樹。s 的一個子樹包括 s 的一個節點和這個節點的所有子孫。s 也可以看做它自身的一棵子樹。 示例 1: 給定的樹 s: 3/ \4 5/ \1 2給定的樹 t&#xff1a; 4 / \1 2返回 true&#x…

二叉樹中序遍歷的三種方法

二叉樹是一種重要的數據結構&#xff0c;對二叉樹的遍歷也很重要。這里簡單介紹三種二叉樹中序遍歷的方法。二叉樹的中序遍歷就是首先遍歷左子樹&#xff0c;然后訪問當前節點&#xff0c;最后遍歷右子樹。對于下面的二叉樹&#xff0c;中序遍歷結果如下&#xff1a; 結果&…

reverse函數:反轉容器內容

reverse函數可以反轉一個容器中的內容&#xff0c;包含在<algorithm>庫中。 1、函數原型 reverse函數等同于下面的代碼&#xff1a; template <class BidirectionalIterator> void reverse (BidirectionalIterator first, BidirectionalIterator last) {while ((…

服務器框架

一、Reactor模式 Reactor模式&#xff0c;它要求主線程&#xff08;I/O處理單元&#xff09;只負責監聽文件描述符上是否有事件發生&#xff0c;有的話就立即將該事件通知工作線程&#xff08;邏輯單元&#xff09;。除此之外&#xff0c;主線程&#xff08;I/O處理單元&#…

使用CreateFile讀寫文件

微軟提供了強大的文件讀寫操作的編程接口&#xff0c;所以可以通過調用API函數實現文件的讀寫操作。這里通過CreateFile函數來實現。 要對文件進行讀寫操作&#xff0c;首先要調用CreateFile函數打開或者創建文件&#xff0c;函數具體格式如下&#xff1a; HANDLE CreateFile(…

Leetcode 9. 回文數(Palindrome Number)

判斷一個整數是否是回文數。回文數是指正序&#xff08;從左向右&#xff09;和倒序&#xff08;從右向左&#xff09;讀都是一樣的整數。 示例 1: 輸入: 121 輸出: true示例 2: 輸入: -121 輸出: false 解釋: 從左向右讀, 為 -121 。 從右向左讀, 為 121- 。因此它不是一個…

使用CreateThread函數創建線程

線程是進程中的一個實體&#xff0c;是被系統獨立調度和分派的基本單位。一個進程可以擁有多個線程&#xff0c;但是一個線程必須有一個進程。線程自己不擁有系統資源&#xff0c;只有運行所必須的一些數據結構&#xff0c;但它可以與同屬于一個進程的其它線程共享進程所擁有的…

Leetcode 16. 最接近的三數之和(3Sum Closest)

解法一&#xff1a; class Solution { public:int threeSumClosest(vector<int>& nums, int target) {int closest nums[0] nums[1] nums[2];int diff abs(closest - target);sort(nums.begin(), nums.end());for (int i 0; i < nums.size() - 2; i) {int…

BMP格式詳解

BMP&#xff08;全稱Bitmap&#xff09;是Windows操作系統中的標準圖像文件格式&#xff0c;可以分成兩類&#xff1a;設備相關位圖&#xff08;DDB&#xff09;和設備無關位圖&#xff08;DIB&#xff09;&#xff0c;使用非常廣。它采用位映射存儲格式&#xff0c;除了圖像深…

Leetcode 5. 最長回文子串(Longest Palindromic Substring)

推薦理由&#xff1a;暴力解法太 naive&#xff0c;中心擴散不普適&#xff0c;Manacher 就更不普適了&#xff0c;是專門解這個問題的方法。而用動態規劃我認為是最有用的&#xff0c;可以幫助你舉一反三的方法。 補充說明&#xff1a;Manacher 算法有興趣的朋友們可以了解一…

請求轉發與請求重定向的區別

請求轉發&#xff1a; 請求轉發&#xff0c;即request.getRequestDispatcher().forward()&#xff0c;是一種服務器的行為&#xff0c;客戶端只有一次請求&#xff0c;服務器端轉發后會將請求對象保存&#xff0c;地址欄中的URL地址不會改變&#xff0c;得到響應后服務器端再將…