#include <arpa/inet.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static int SERV_PORT = 6666;
int main(int argc, char** argv) {
int i = 0, j = 0, n = 0, maxi = 0;
int nready, client[FD_SETSIZE];
int maxfd, listenfd, connfd, sockfd;
char buf[BUFSIZ], str[INET_ADDRSTRLEN];
struct sockaddr_in clie_addr, serv_addr;
socklen_t clie_addr_len;
fd_set rset, allset;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd == -1) {
perror("socket()");
exit(1);
}
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int be = bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
if (be == -1) {
perror("bind()");
exit(1);
}
int le = listen(listenfd, SOMAXCONN);
if (le == -1) {
perror("listen()");
exit(1);
}
maxfd = listenfd;
maxi = -1;
for (int i = 0; i < FD_SETSIZE; i++) client[i] = -1;
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
while (1) {
rset = allset;
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if (nready < 0) {
perror("select()");
exit(1);
}
if (FD_ISSET(listenfd, &rset)) {
clie_addr_len = sizeof(clie_addr);
connfd = accept(listenfd, (struct sockaddr*)&clie_addr, &clie_addr_len);
printf("received from %s at PORT %d \n",
inet_ntop(AF_INET, &clie_addr.sin_addr, str, sizeof(str)),
ntohs(clie_addr.sin_port));
for (i = 0; i < FD_SETSIZE; ++i) {
if (client[i] < 0) {
client[i] = connfd; // 找到空位赋值
break;
}
}
if (i == FD_SETSIZE) {
fputs("too many client connections\n", stderr);
exit(1);
}
FD_SET(connfd, &allset); // 加入文件描述符
if (connfd > maxfd) maxfd = connfd; // 更新maxfd
if (i > maxi) maxi = i; // 更新数组上限指针
if (--nready ==0)
continue;
}
printf("complete accept\n");
for (i = 0; i <= maxi; ++i) { // 检测哪个clients有数据就绪
if ((sockfd = client[i]) < 0) continue;
if (FD_ISSET(sockfd, &rset)) {
printf("complete ISSET\n");
if ((n = read(sockfd, buf, sizeof(buf))) == 0) { //是否关闭client
printf("close()\n");
close(sockfd); //清理操作
FD_CLR(sockfd, &allset); // 客户端关闭也会导致产生read事件
client[i] = -1;
} else if (n > 0) {
int we = write(STDOUT_FILENO, buf, n);
if (we == -1) {
perror("write");
}
we = write(sockfd, buf, n);
if (we == -1) {
perror("write");
}
}
if (--nready == 0) break;
}
}
}
close(listenfd);
return 0;
}
其实就是unp的例子,看到每此accept之后都可能会进入读写,但是如果在这个时候,客户端发来消息,那么下次select()会响应这个事件吗?
我觉得不会,是不是unp上的例子是有bug的?