1、select函数
#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);
demo示例
#include "wrap.h"
#include <sys/select.h>
#include <arpa/inet.h>
#include <strings.h>
#include <ctype.h>
void exchange(char *buf, int len);
int main(){
// socket
int sfd, cfd;
sfd = Socket(AF_INET, SOCK_STREAM, 0);
int sockopt = 1;
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));
// bind linsten
struct sockaddr_in s_addr, c_addr;
socklen_t addrlen = sizeof(struct sockaddr_in);
bzero(&s_addr, addrlen);
bzero(&c_addr, addrlen);
s_addr.sin_family = AF_INET;
s_addr.sin_addr.s_addr = htonl(INADDR_ANY);
s_addr.sin_port = htons(3000);
Bind(sfd, &s_addr, sizeof(s_addr));
Listen(sfd, 128);
// fd_set、nfds、client[]、select
fd_set readfds, allfds;
FD_ZERO(&readfds);
FD_ZERO(&allfds);
FD_SET(sfd, &allfds);
int maxfd = sfd;
int selret;
int client[FD_SETSIZE], i, maxi = -1;
for (i = 0; i < FD_SETSIZE; i++){
client[i] = -1;
}
while(1){
readfds = allfds;
// select函数(阻塞)
selret = select(maxfd + 1, &readfds, NULL, NULL, NULL);
if (selret < 0){
perror("select error");
exit(1);
}
// 1、是否有新连接,创建连接,处理新建连接请求(文件描述符公用,生产其他文件描述符)
if (FD_ISSET(sfd, &readfds)){
// 1.1、创建连接
cfd = Accept(sfd, &c_addr, &addrlen);
char address[INET_ADDRSTRLEN];
printf("A new connect from %s:%d\n",
inet_ntop(AF_INET, &c_addr.sin_addr.s_addr, address, INET_ADDRSTRLEN),
ntohs(c_addr.sin_port));
// 1.2、将新的文件描述符加入到数组
for (i = 0; i < FD_SETSIZE; i++){
if (client[i] != -1) continue;
client[i] = cfd;
break;
}
if (maxi < i) maxi = i;
if (maxfd < cfd) maxfd = cfd;
// 1.3、将新的文件描述符加入到集合
FD_SET(cfd, &allfds);
if (--selret == 0) continue;
}
// 2、现有连接数据处理
for (i = 0; i <= maxi; i++){
int fd = client[i];
if (fd == -1) continue;
if (FD_ISSET(fd, &readfds)){
// 处理数据
char buf[BUFSIZ];
int n = Readn(fd, &buf, BUFSIZ);
if (n <= 0){
close(fd);
client[i] = -1;
FD_CLR(fd, &allfds);
continue;
}else{
printf("readed %d bytes\n", n);
exchange(buf, n);
write(fd, buf, n);
}
if (--selret == 0) break;
}
}
}
}
void exchange(char *buf, int len)
{
int i;
for (i = 0; i < len; i++){
buf[i] = toupper(buf[i]);
}
}
2、poll函数
- 修改文件描述符限制:/proc/sys/fs/file-max
- 修改文件描述符限制仅对poll及epoll有效,对select无效,select的文件描述符上限FD_SETSIZE由unix内核限制了,修改需要重新编译内核;
* soft nofile 65535
* hard nofile 100000
SYNOPSIS
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
DESCRIPTION
poll() performs a similar task to select(2): it waits for one of a set of file descriptors to become ready to perform I/O.
The set of file descriptors to be monitored is specified in the fds argument, which is an array of structures of the following form:
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
The caller should specify the number of items in the fds array in nfds.
#include "wrap.h"
#include <arpa/inet.h>
#include <ctype.h>
#include <strings.h>
#include <poll.h>
#define OPEN_MAX 1024
int main(){
// socket
int sfd, cfd;
sfd = Socket(AF_INET, SOCK_STREAM, 0);
// bind
struct sockaddr_in s_addr, c_addr;
socklen_t addrlen = sizeof(struct sockaddr_in);
bzero(&s_addr, addrlen);
bzero(&c_addr, addrlen);
s_addr.sin_family = AF_INET;
s_addr.sin_addr.s_addr = htonl(INADDR_ANY);
s_addr.sin_port = htons(3000);
int sockopt = 1;
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));
Bind(sfd, &s_addr, addrlen);
Listen(sfd, 128);
// pollfd
struct pollfd fds[OPEN_MAX];
fds[0].fd = sfd;
fds[0].events = POLLIN;
int i, maxi;
for(i = 1; i < OPEN_MAX; i++){
fds[i].fd = -1;
}
maxi = 0;
nfds_t maxfd = sfd;
int pollret;
while(1){
pollret = poll(fds, maxfd + 1, -1);
if (pollret < 0){
perror("poll error");
exit(1);
}
// 1、判断是否有新连接
if (fds[0].revents & POLLIN){
cfd = Accept(sfd, &c_addr, &addrlen);
char address[INET_ADDRSTRLEN];
printf("A new client -- %s:%d\n",
inet_ntop(AF_INET, &c_addr.sin_addr.s_addr, address, INET_ADDRSTRLEN),
ntohs(c_addr.sin_port));
for(i = 1; i < OPEN_MAX; i++){
if (fds[i].fd != -1) continue;
fds[i].fd = cfd;
fds[i].events = POLLIN;
break;
}
if (maxfd < cfd) maxfd = cfd;
if (maxi < i) maxi = i;
if (--pollret == 0) continue;
}
// 2、判断是否有数据交互
for (i = 1; i <= maxi; i++){
int fd = fds[i].fd;
if (fd == -1) continue;
// 有读数据
if (fds[i].revents & POLLIN){
char buf[BUFSIZ];
int n = Readn(fd, buf, BUFSIZ);
printf("readed %d bytes\n", n);
if (n <= 0){
close(fd);
fds[i].fd = -1;
continue;
}
// 处理数据
for (i = 0; i < n; i++){
buf[i] = toupper(buf[i]);
}
write(fd, buf, n);
if (--pollret == -1) break;
}
}
}
return 0;
}