select函数说明
select函数原型:
int select(int nfds, fd_set *rdfds, fd_set *wtfds, fd_set *exfds, struct timeval *timeout)
select函数有两点限制:
进程能够打开的最大文件描述符个数
select函数中,fd_set集合所能够容纳的最大文件描述符个数
函数实例代码
#include
#include /* basic system data types */
#include /* basic socket definitions */
#include /* sockaddr_in{} and other Internet defns */
#include /* inet(3) functions */
#include /* select function*/
#include
#include
#include
#include
#define MAXLINE 10240
void handle(int * clientSockFds, int maxFds, fd_set* pRset, fd_set* pAllset);
int main(int argc, char **argv)
{
int servPort = 6888; // 服务器端口
int listenq = 1024;
int listenfd, connfd; // 监听套接字,已连接套接字
struct sockaddr_in cliaddr, servaddr; // 定义服务器,客户端地址结构体
socklen_t socklen = sizeof(struct sockaddr_in);
int nready, nread;
char buf[MAXLINE];
int clientSockFds[FD_SETSIZE];
fd_set allset, rset;
int maxfd;
listenfd = socket(AF_INET, SOCK_STREAM, 0); // 创建监听套接字
if (listenfd < 0) {
perror("socket error");
return -1;
}
int opt = 1;
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
perror("setsockopt error");
}
// 向服务器地址结构体中的各个字段赋值
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(servPort);
// 绑定监听套接字和服务器地址
if(bind(listenfd, (struct sockaddr*)&servaddr, socklen) == -1) {
perror("bind error");
exit(-1);
}
if (listen(listenfd, listenq) < 0) {
perror("listen error");
return -1;
}
int i = 0;
for (i = 0; i< FD_SETSIZE; i++)
clientSockFds[i] = -1;
FD_ZERO(&allset); // 情况文件描述符集合
FD_SET(listenfd, &allset); // 将监听套接字加入文件描述符集合
maxfd = listenfd;
printf("echo server use select startup, listen on port %d\n", servPort);
printf("max connection: %d\n", FD_SETSIZE);
for ( ; ; ) {
rset = allset; // 将套接字集合赋值给reset
// nready是..
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if (nready < 0) {
perror("select error");
continue;
}
// 如果监听套接字有返回
if (FD_ISSET(listenfd, &rset)) {
// 建立连接,返回已连接套接字
connfd = accept(listenfd, (struct sockaddr*) &cliaddr, &socklen);
if (connfd < 0) {
perror("accept error");
continue;
}
// 打印对等方信息
sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
printf(buf, "");
// 将已连接套接字加入套接字存放的数组
for (i = 0; i< FD_SETSIZE; i++) { if (clientSockFds[i] == -1) { clientSockFds[i] = connfd; break; } } // 如果套接字存放数组中没有空闲的地方,则关闭 if (i == FD_SETSIZE) { fprintf(stderr, "too many connection, more than %d\n", FD_SETSIZE); close(connfd); continue; } // 已连接套接字的文件描述符是否是最大的,如果是,则更新 if (connfd > maxfd)
maxfd = connfd;
// 将已连接套接字放入套接字集合
FD_SET(connfd, &allset);
if (--nready <= 0)
continue;
}
// 存放套接字数组,最大套接字文件描述符,套接字集合
handle(clientSockFds, maxfd, &rset, &allset);
}
}
void handle(int * clientSockFds, int maxFds, fd_set* pRset, fd_set* pAllset) {
int nread;
int i;
char buf[MAXLINE];
for (i = 0; i< maxFds; i++) {
if (clientSockFds[i] != -1) {
if (FD_ISSET(clientSockFds[i], pRset)) {
nread = read(clientSockFds[i], buf, MAXLINE);//读取客户端socket流
if (nread < 0) {
perror("read error");
close(clientSockFds[i]);
FD_CLR(clientSockFds[i], pAllset);
clientSockFds[i] = -1;
continue;
}
if (nread == 0) {
printf("client close the connection\n");
close(clientSockFds[i]);
FD_CLR(clientSockFds[i], pAllset);
clientSockFds[i] = -1;
continue;
}
write(clientSockFds[i], buf, nread);//响应客户端 有可能失败,暂不处理
}
}
}
}
实例代码函数流程图
一直觉得函数比较绕,就根据该实例画了流程图,可能有不正确的地方,希望能够被指出
喜欢 (0)or分享 (0)