#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SERV_PORT 1111
#define MAXLINE 128
int main(void)
{
int i = 0,sockfd;
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in client_addr, server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(SERV_PORT);
bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr));
listen(listenfd, 20);
int maxfd = listenfd;
fd_set rset, allset;
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
int client[FD_SETSIZE]; /* FD_SETSIZE 默认为 1024 */
int maxi = -1;
while(1)
{
rset = allset;
int nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if(nready < 0)
{
perror("select error");
return -1;
}
if(FD_ISSET(listenfd, &rset))
{
int client_addr_len = sizeof(client_addr);
int connfd = accept(listenfd, (struct sockaddr *)&client_addr, &client_addr_len);
char str[INET_ADDRSTRLEN];
printf("received connection from %s at port %d\n", inet_ntop(AF_INET, &client_addr,str, sizeof(str)), ntohs(client_addr.sin_port));
for (i = 0; i < FD_SETSIZE; i++){
if(client[i] < 0){
client[i] = connfd; /* 保存accept返回的文件描述符到client[]里 */
break;
}
}
/* 达到select能监控的文件个数上限 1024 */
if(i == FD_SETSIZE){
printf("too many clients\n");
return -1;
}
FD_SET(connfd, &allset);/* 添加一个新的文件描述符到监控信号集里 */
if (connfd > maxfd)
maxfd = connfd; /* select第一个参数需要 */
if (i > maxi)
maxi = i; /* 更新client[]最大下标值 */
if (--nready == 0)
continue; /* 如果没有更多的就绪文件描述符继续回到上面select阻塞监听,负责处理未处理完的就绪文件描述符 */
}
int n;
char buf[MAXLINE];
for (i = 0; i <= maxi; i++) { /* 检测哪个clients 有数据就绪 */
sockfd = client[i];
if(sockfd < 0)
continue;
if (FD_ISSET(sockfd, &rset)) {
if ( (n = read(sockfd, buf, MAXLINE)) == 0) {
/* 当client关闭链接时,服务器端也关闭对应链接 */
close(sockfd);
FD_CLR(sockfd, &allset); /* 解除select监控此文件描述符 */
client[i] = -1;
} else {
int j;
for (j = 0; j < n; j++)
buf[j] = toupper(buf[j]);
write(sockfd, buf, n);
}
if (--nready == 0)
break;
}
}
}
return 0;
}
epool_server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <errno.h>
#include "wrap.h"
#define MAXLINE 80
#define SERV_PORT 8000
#define OPEN_MAX 1024
int main(int argc, char *argv[])
{
int i, j, maxi, listenfd, connfd, sockfd;
int nready, efd, res;
ssize_t n;
char buf[MAXLINE], str[INET_ADDRSTRLEN];
socklen_t clilen;
int client[OPEN_MAX];
struct sockaddr_in cliaddr, servaddr;
struct epoll_event tep, ep[OPEN_MAX];
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
Listen(listenfd, 20);
for (i = 0; i < OPEN_MAX; i++)
client[i] = -1;
maxi = -1;
efd = epoll_create(OPEN_MAX);
if (efd == -1)
perr_exit("epoll_create");
tep.events = EPOLLIN;
tep.data.fd = listenfd;
res = epoll_ctl(efd, EPOLL_CTL_ADD, listenfd, &tep);
if (res == -1)
perr_exit("epoll_ctl");
while(1)
{
nready = epoll_wait(efd, ep, OPEN_MAX, -1); /* 阻塞监听 */
if (nready == -1)
perr_exit("epoll_wait");
for (i = 0; i < nready; i++)
{
if (!(ep[i].events & EPOLLIN))
continue;
//如果是监听fd,则要加入epool
if (ep[i].data.fd == listenfd)
{
clilen = sizeof(cliaddr);
connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
printf("received from %s at PORT %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port));
for (j = 0; j < OPEN_MAX; j++)
{
if (client[j] < 0)
{
client[j] = connfd; /* save descriptor */
break;
}
}
if (j == OPEN_MAX)
perr_exit("too many clients");
if (j > maxi)
maxi = j; /* max index in client[] array */
tep.events = EPOLLIN;
tep.data.fd = connfd;
res = epoll_ctl(efd, EPOLL_CTL_ADD, connfd, &tep);
if (res == -1)
perr_exit("epoll_ctl");
}
else
{
sockfd = ep[i].data.fd;
n = Read(sockfd, buf, MAXLINE);
//如果读取的字节是0,说明对方关闭了,那么我们需要减少该fd
if (n == 0)
{
for (j = 0; j <= maxi; j++)
{
if (client[j] == sockfd)
{
client[j] = -1;
break;
}
}
res = epoll_ctl(efd, EPOLL_CTL_DEL, sockfd, NULL);
if (res == -1)
perr_exit("epoll_ctl");
Close(sockfd);
printf("client[%d] closed connection\n", j);
}
else
{
for (j = 0; j < n; j++)
buf[j] = toupper(buf[j]);
Writen(sockfd, buf, n);
}
}
}
}