一.底层原理:本质是上委托内核去检测通信过程中文件描述符的一系列状态
二.select 函数详解:
首先我在Ubuntu上使用man查看一下帮助手册:

函数一共有五个参数:1.nfds:检测文件描述符集合中最大描述符+1;
2.readfds:读集合
3.writefds:写集合
4.exceptfds:异常集合
5.timeout:最长时间
函数解释:
fd_set是一个文件描述符集合,用于select函数。FD_ZERO初始化集合,清空所有文件描述符。FD_SET将监听套接字fd添加到集合中。
服务器代码:
include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, const char* argv[]) {
int lfd = socket(AF_INET, SOCK_STREAM, 0); // 创建监听套接字
if (lfd == -1) {
std::cout << "socket error" << std::endl;
exit(0);
}
struct sockaddr_in ser_addr;
memset(&ser_addr, 0, sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_port = htons(9999);
ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
// 绑定端口
int ret = bind(lfd, (struct sockaddr*)&ser_addr, sizeof(ser_addr));
if (ret == -1) {
std::cout << "bind error" << std::endl;
exit(1);
}
// 监听
ret = listen(lfd, 64);
if (ret == -1) {
std::cout << "listen error" << std::endl;
exit(1);
}
fd_set redset;
FD_ZERO(&redset);
FD_SET(lfd, &redset);
int maxfd = lfd;
while (1) {
fd_set tmp = redset;
int ret = select(maxfd + 1, &tmp, NULL, NULL, NULL);
// 处理监听套接字
if (FD_ISSET(lfd, &tmp)) {
int cfd = accept(lfd, NULL, NULL);
if (cfd == -1) {
std::cout << "accept error" << std::endl;
exit(1);
}
FD_SET(cfd, &redset);
if (cfd > maxfd) {
maxfd = cfd;
}
}
// 处理客户端套接字
for (int i = 0; i <= maxfd; i++) {
if (i != lfd && FD_ISSET(i, &tmp)) {
char buf[1024];
int len = recv(i, buf, sizeof(buf), 0);
if (len == -1) {
std::cout << "recv error" << std::endl;
exit(1);
} else if (len == 0) {
FD_CLR(i, &redset);
close(i);
std::cout << "client is closed" << std::endl;
break;
}
// 转换为大写
for (int j = 0; j < len; j++) {
buf[j] = toupper(buf[j]);
std::cout << "alter buf: " << buf[j] << std::endl;
}
ret = send(i, buf, strlen(buf) + 1, 0);
if (ret == -1) {
std::cout << "send error" << std::endl;
}
}
}
}
close(lfd);
return 0;
}
运行结果如下:

由于没有客户端连接,程序一直阻塞,现在我们找一个博主最近写的项目(后续做完也会在本网站上开源和发布)

博主在这里设置当连接成功后程序才能跑起来,显然博主写的大概没啥问题。今天的文章就更新到这了。
评论
还没有任何评论,你来说两句吧!