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.mzph.cn/news/385508.shtml

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

相关文章

Redis高级项目实战,阿里P7级别面试经验总结

第一次压测 惨不忍睹&#xff0c;平均响应时间150ms&#xff0c;而且在这次压测过程中还发现其它的问题&#xff0c;后台报错&#xff0c;经查是OpenSearch每秒查询次数限制 优化代码与配置 1、修改OpenSearch配置&#xff0c;并且将压测环境中的OpenSearch连接地址改为内网地…

Redis高频面试笔记:java版本号比较算法

1.三重心智模型 先给大家科普一个概念&#xff0c;“三重心智模型”。 认知科学家斯坦诺维奇&#xff0c;将人的心智模式&#xff0c;分成了三个部分。 第一层是自主心智&#xff0c;自主心智是我们通过进化与内隐学习获得。比如&#xff0c;我们看到蛇就会害怕&#xff0c;情…

Redis高频面试笔记:mysql8.0新特性

一、服务发布简介 分布式系统架构下&#xff0c;服务发布是一件很麻烦的事情&#xff0c;特别是在构建自动发布流程和灰度测试的策略两个核心方面。通常情况下如果不涉及数据层面的灰度流程&#xff0c;服务可以灰度上线&#xff0c;或者滚动上线&#xff0c;这两种方式很常用…

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

1. Java 堆空间 **发生频率&#xff1a;**5颗星 造成原因 无法在 Java 堆中分配对象 吞吐量增加 应用程序无意中保存了对象引用&#xff0c;对象无法被 GC 回收 应用程序过度使用 finalizer。finalizer 对象不能被 GC 立刻回收。finalizer 由结束队列服务的守护线程调用&a…

二叉树中序遍历的三种方法

二叉树是一种重要的数据结构&#xff0c;对二叉树的遍历也很重要。这里简单介绍三种二叉树中序遍历的方法。二叉树的中序遍历就是首先遍历左子树&#xff0c;然后访问当前节点&#xff0c;最后遍历右子树。对于下面的二叉树&#xff0c;中序遍历结果如下&#xff1a; 结果&…

服务器框架

一、Reactor模式 Reactor模式&#xff0c;它要求主线程&#xff08;I/O处理单元&#xff09;只负责监听文件描述符上是否有事件发生&#xff0c;有的话就立即将该事件通知工作线程&#xff08;逻辑单元&#xff09;。除此之外&#xff0c;主线程&#xff08;I/O处理单元&#…

使用CreateFile读写文件

微软提供了强大的文件读写操作的编程接口&#xff0c;所以可以通过调用API函数实现文件的读写操作。这里通过CreateFile函数来实现。 要对文件进行读写操作&#xff0c;首先要调用CreateFile函数打开或者创建文件&#xff0c;函数具体格式如下&#xff1a; HANDLE CreateFile(…

使用CreateThread函数创建线程

线程是进程中的一个实体&#xff0c;是被系统独立调度和分派的基本单位。一个进程可以拥有多个线程&#xff0c;但是一个线程必须有一个进程。线程自己不拥有系统资源&#xff0c;只有运行所必须的一些数据结构&#xff0c;但它可以与同属于一个进程的其它线程共享进程所拥有的…

BMP格式详解

BMP&#xff08;全称Bitmap&#xff09;是Windows操作系统中的标准图像文件格式&#xff0c;可以分成两类&#xff1a;设备相关位图&#xff08;DDB&#xff09;和设备无关位图&#xff08;DIB&#xff09;&#xff0c;使用非常广。它采用位映射存储格式&#xff0c;除了图像深…

请求转发与请求重定向的区别

请求转发&#xff1a; 请求转发&#xff0c;即request.getRequestDispatcher().forward()&#xff0c;是一种服务器的行为&#xff0c;客户端只有一次请求&#xff0c;服务器端转发后会将请求对象保存&#xff0c;地址栏中的URL地址不会改变&#xff0c;得到响应后服务器端再将…

StringBuilder详解

1、简介 StringBuilder和StringBuffer一样&#xff0c;都是继承自抽象类AbstractStringBuilder类&#xff0c;也是一个可变的字符序列。StringBuilder和StringBuffer非常相似&#xff0c;甚至有互相兼容的API&#xff0c;不过&#xff0c;StringBuilder不是线程安全的&#xf…

【线程】互斥锁

一、互斥锁 1. 函数原型 pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); pthread_mutex_destroy(pthread_mutex_t *mutex); 分析&#xff1a; pthread_mutex_t 类型&#xff0c;其本质是一个结构体&#xff0c;为简化…

ArrayList详解

1、简介 ArrayList是Java集合框架中的一个重要的类&#xff0c;它继承于AbstractList&#xff0c;实现了List接口&#xff0c;是一个长度可变的集合&#xff0c;提供了增删改查的功能。集合中允许null的存在。ArrayList类还是实现了RandomAccess接口&#xff0c;可以对元素进行…

【进程】进程组

一、进程组 1. 进程组 &#xff08;1&#xff09;进程组&#xff0c;也称之为作业&#xff0c;BSD与1980年前后向UNIX中增加的一个新特性&#xff0c;代表一个或多个进程的集合。每个进程都属于一个进程组&#xff0c;在waitpid函数和kill函数的参数中都曾经使用到&#xff0c…

函数wait、waitpid、孤儿进程、僵尸进程

一、函数wait、waitpid 一个进程在终止时会关闭所有文件描述符&#xff0c;释放在用户空间释放的内存&#xff0c;但它的PCB还保留着&#xff0c;内核在其中保存一些信息&#xff1a;如果是正常终止时则保存着退出状态&#xff0c;如果是异常终止则保存着导致该进程终止的信号是…

MySQL中的字符集与字符序

这篇文章详细介绍一下MySQL中的字符集和字符序相关的问题&#xff0c;里里外外地了解一下字符集和字符序的方方面面&#xff0c;同时重点说明一下开发中需要注意的问题。 文章基于MySQL 8.0&#xff0c;也会涉及到5.7版本。主要参考MySQL手册&#xff1a;https://dev.mysql.com…

【C++ Primer | 15】虚函数表剖析(一)

一、虚函数 1. 概念 多态指当不同的对象收到相同的消息时&#xff0c;产生不同的动作 编译时多态&#xff08;静态绑定&#xff09;&#xff0c;函数重载&#xff0c;运算符重载&#xff0c;模板。运行时多态&#xff08;动态绑定&#xff09;&#xff0c;虚函数机制。为了实现…

Leetcode 118. 杨辉三角

给定一个非负整数 numRows&#xff0c;生成杨辉三角的前 numRows 行。 在杨辉三角中&#xff0c;每个数是它左上方和右上方的数的和。 示例: 输入: 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1] ] class Solution { public:vector<vector<int>> generate(…

Linux本地yum源配置以及使用yum源安装各种应用程序

将软件包传送到Linux中后&#xff0c;挂载&#xff0c;然后配置yum软件仓库&#xff0c;最后就可以使用yum来安装相应的应用程序了。假设挂载目录为/tmp/ruanjianbao&#xff0c;则下面说明配置本地yum仓库的过程&#xff1a; &#xff08;1&#xff09;cd /etc/yum.repos.d/…

【第15章】多重继承

1. 虚基类介绍 多继承时很容易产生命名冲突&#xff0c;即使我们很小心地将所有类中的成员变量和成员函数都命名为不同的名字&#xff0c;命名冲突依然有可能发生&#xff0c;比如非常经典的菱形继承层次。如下图所示&#xff1a; 类A派生出类B和类C&#xff0c;类D继承自类B和…