#include <asm-generic/socket.h>
#include <cctype>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <netinet/in.h>
#include <strings.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "sock_wrapper.h"
const static uint16_t kPort = 4433;
const static char *kIpStr = "192.168.3.20";
int main() {
char buffer[BUFSIZ];
int listenFd = socket(AF_INET, SOCK_STREAM, 0);
int reuse = 1;
setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (const void *)&reuse, sizeof(reuse));
sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(kPort);
inet_pton(AF_INET, kIpStr, &addr.sin_addr);
int ret = bind(listenFd, (const struct sockaddr *)&addr, sizeof(addr));
if (ret < 0) {
perror("bind error.\n");
return -1;
}
//设置最同时监听上限
ret = listen(listenFd, 125);
if (ret < 0) {
perror("list error.\n");
return -1;
}
//在linux上是一个大小为1024的bit数组,大小由FD_SETSIZE决定
fd_set all_set;
//可以理解成对刚分配的all_set内存进行初始化操作
//这一步是必须的,否则可能出现内存问题
FD_ZERO(&all_set);
//将对应的文件描述符,加入到set中
FD_SET(listenFd, &all_set);
int maxFd = listenFd;
while (1) {
fd_set r_set = all_set;
//第一个参数是监听的三个文件描述符集合的最大文件描述符 +1
//第二个参数是一个传入传出参数:传入:要监听读取事件的文件描述符表,传出:有读取事件发生的文件描述符
//其他的分别是写入事件,异常事件,没有的话可以传空
//最后一个参数:表示阻塞等待的时间,如果为NULL表示一直阻塞,他是一个指针类型
//返回值表示:发生事件的全部文件描述符个数
int selectNum = select(maxFd + 1, &r_set, nullptr, nullptr, NULL);
if (selectNum < 0) {
perror("select error\n");
exit(-1);
}
//判断是否是监听socket上有读事件,如果是,则应该调用accept Api
if (FD_ISSET(listenFd, &r_set)) {
sockaddr_in clientAddr;
bzero(&clientAddr, sizeof(clientAddr));
socklen_t clientLen = sizeof(clientAddr);
int connFd = accept(listenFd, (struct sockaddr *)&addr, &clientLen);
if (connFd < 0) {
perror("accept error\n");
exit(0);
}
//将新接入联通的文件描述符加入到监听观察集合中
FD_SET(connFd, &all_set);
//检测更新最大文件描述符
if (maxFd < connFd) {
maxFd = connFd;
}
//表示只有一个文件描述符上有事件发生,并且这个事件赢被处理,因此不需要在后续的处理
if (selectNum == 1) {
continue;
}
}
//客户端连接文件描述符上存在事件发生,则循环遍历所以监听的文件描述符
for (int connFd = listenFd + 1; connFd < maxFd + 1; ++connFd) {
if (FD_ISSET(connFd, &r_set)) {
int readNum = read(connFd, (void *)buffer, sizeof(buffer));
if (readNum < 0) {
perror("read_bytes error.");
exit(-1);
}
//读取的数为0时,表示对端socket关闭了
if (readNum == 0) {
//这里有个问题,当connFd关闭时,如果是当前最大文件描述符,则没有更新最大文件描述符
close(connFd);
//将文件描述符从set中移除
FD_CLR(connFd, &all_set);
printf("close client \n");
break;
}
//处理数据
printf("server receive: %s\n",buffer);
for (int i = 0; i < readNum; ++i) {
buffer[i] = toupper(buffer[i]);
}
//结果会写给对端
int writeNum = write(connFd, buffer, readNum);
if (writeNum < 0) {
perror("write error");
exit(-1);
} else {
printf("server response success.\n");
}
}
}
}
close(listenFd);
return 0;
}
Linux网络编程:Select
猜你喜欢
转载自blog.csdn.net/xiwenhec/article/details/129391926
今日推荐
周排行