您的位置:首页 > 其它

select在并发中的两点限制与poll函数的使用

2014-05-13 19:44 477 查看
用select实现的并发服务器,能达到的并发数,受两方面限制:
一个进程能打开的最大文件描述符限制。这可以通过调整内核参数。
select中的fd_set集合容量的限制(FD_SETSIZE) ,这需要重新编译内核。//这个不能通过调整内核参数来限制 FD_SETSIZE宏等于1024在一个头文件中设置 改变它需要重新编译内核。

ulinit -n来查询最大文件描述符 得到1024 可以通过sudo bash 换位root用户 ulimit -n 2048进行修改最大文件描述符 man getrlimit 其中三个被标准输入 标准输出 标准错误 监听套接字给占用 实际使用只有1020个文件描述符

poll函数没有FD_SETSIZE的限制(与select用法差不多)

一个进程能打开的最大文件描述个数是有限的

ulinit -n number可以进行设置最大文件描述个数

系统能打开的最大文件描述个数是 有限的 ,跟内存大小有关。

共同点:

内核要遍历所有文件描述符,直到找到发生事件的文件描述符。(因为要遍历所有文件描述符,所以随着并发数增长时,效率不高,可以通过epoll来解决这个问题。)


q#include <poll.h>
qint poll(struct pollfd *fds, nfds_t nfds, int timeout);我们要关注的I/O与事件加入到第一个参数中即可 第二个I/O的个数 第三个参数是超时的时间

只受一个进程能打开的最大文件描述符限制。这可以通过调整内核参数。pollfd一个结构体内含有fd,events,return events.可通过man poll查询。

pollsrv.c

#include <unistd.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <signal.h>

#include <sys/wait.h>

#include <poll.h>

#include <stdlib.h>

#include <stdio.h>

#include <errno.h>

#include <string.h>

#define ERR_EXIT(m) \

do \

{ \

perror(m); \

exit(EXIT_FAILURE); \

} while(0)

ssize_t readn(int fd, void *buf, size_t count)

{

size_t nleft = count;

ssize_t nread;

char *bufp = (char*)buf;

while (nleft > 0)

{

if ((nread = read(fd, bufp, nleft)) < 0)

{

if (errno == EINTR)

continue;

return -1;

}

else if (nread == 0)

return count - nleft;

bufp += nread;

nleft -= nread;

}

return count;

}

ssize_t writen(int fd, const void *buf, size_t count)

{

size_t nleft = count;

ssize_t nwritten;

char *bufp = (char*)buf;

while (nleft > 0)

{

if ((nwritten = write(fd, bufp, nleft)) < 0)

{

if (errno == EINTR)

continue;

return -1;

}

else if (nwritten == 0)

continue;

bufp += nwritten;

nleft -= nwritten;

}

return count;

}

ssize_t recv_peek(int sockfd, void *buf, size_t len)

{

while (1)

{

int ret = recv(sockfd, buf, len, MSG_PEEK);

if (ret == -1 && errno == EINTR)

continue;

return ret;

}

}

ssize_t readline(int sockfd, void *buf, size_t maxline)

{

int ret;

int nread;

char *bufp = buf;

int nleft = maxline;

while (1)

{

ret = recv_peek(sockfd, bufp, nleft);

if (ret < 0)

return ret;

else if (ret == 0)

return ret;

nread = ret;

int i;

for (i=0; i<nread; i++)

{

if (bufp[i] == '\n')

{

ret = readn(sockfd, bufp, i+1);

if (ret != i+1)

exit(EXIT_FAILURE);

return ret;

}

}

if (nread > nleft)

exit(EXIT_FAILURE);

nleft -= nread;

ret = readn(sockfd, bufp, nread);

if (ret != nread)

exit(EXIT_FAILURE);

bufp += nread;

}

return -1;

}

void echo_srv(int conn)

{

char recvbuf[1024];

while (1)

{

memset(recvbuf, 0, sizeof(recvbuf));

int ret = readline(conn, recvbuf, 1024);

if (ret == -1)

ERR_EXIT("readline");

if (ret == 0)

{

printf("client close\n");

break;

}



fputs(recvbuf, stdout);

writen(conn, recvbuf, strlen(recvbuf));

}

}

void handle_sigchld(int sig)

{

/* wait(NULL);*/

while (waitpid(-1, NULL, WNOHANG) > 0)

;

}

void handle_sigpipe(int sig)

{

printf("recv a sig=%d\n", sig);

}

int main(void)

{

int count = 0;

signal(SIGPIPE, handle_sigpipe);

signal(SIGCHLD, handle_sigchld);

int listenfd;

if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)

ERR_EXIT("socket");

struct sockaddr_in servaddr;

memset(&servaddr, 0, sizeof(servaddr));

servaddr.sin_family = AF_INET;

servaddr.sin_port = htons(5188);

servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

int on = 1;

if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)

ERR_EXIT("setsockopt");

if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)

ERR_EXIT("bind");

if (listen(listenfd, SOMAXCONN) < 0)

ERR_EXIT("listen");

struct sockaddr_in peeraddr;

socklen_t peerlen;

int conn;

int i;

struct pollfd client[2048];

int maxi = 0;

for (i=0; i<2048; i++)

client[i].fd = -1;

int nready;

client[0].fd = listenfd;

client[0].events = POLLIN;

while (1)

{

nready = poll(client, maxi+1, -1);

if (nready == -1)

{

if (errno == EINTR)

continue;



ERR_EXIT("select");

}

if (nready == 0)

continue;

if (client[0].revents & POLLIN)

{

peerlen = sizeof(peeraddr);

conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen);

if (conn == -1)

ERR_EXIT("accept");

for (i=0; i<2048; i++)

{

if (client[i].fd < 0)

{

client[i].fd = conn;

if (i > maxi)

maxi = i;

break;

}

}

if (i == 2048)

{

fprintf(stderr, "too many clients\n");

exit(EXIT_FAILURE);

}

printf("ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));

printf("count = %d\n", ++count);



client[i].events = POLLIN;



if (--nready <= 0)

continue;

}

for (i=1; i<=maxi; i++)

{

conn = client[i].fd;

if (conn == -1)

continue;

if (client[i].events & POLLIN)

{

char recvbuf[1024] = {0};

int ret = readline(conn, recvbuf, 1024);

if (ret == -1)

ERR_EXIT("readline");

if (ret == 0)

{

printf("client close\n");

client[i].fd = -1;

close(conn);

}

fputs(recvbuf, stdout);

writen(conn, recvbuf, strlen(recvbuf));

if (--nready <= 0)

break;



}

}

}

return 0;

}

makefile:

.PHONY:clean all

CC=gcc

CFLAGS=-Wall -g

BIN= echocli conntest pollsrv

all:$(BIN)

%.o:%.c

$(CC) $(CFLAGS) -c $< -o $@

clean:

rm -f *.o $(BIN)

echocli.c

#include <unistd.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <signal.h>

#include <stdlib.h>

#include <stdio.h>

#include <errno.h>

#include <string.h>

#define ERR_EXIT(m) \

do \

{ \

perror(m); \

exit(EXIT_FAILURE); \

} while(0)

ssize_t readn(int fd, void *buf, size_t count)

{

size_t nleft = count;

ssize_t nread;

char *bufp = (char*)buf;

while (nleft > 0)

{

if ((nread = read(fd, bufp, nleft)) < 0)

{

if (errno == EINTR)

continue;

return -1;

}

else if (nread == 0)

return count - nleft;

bufp += nread;

nleft -= nread;

}

return count;

}

ssize_t writen(int fd, const void *buf, size_t count)

{

size_t nleft = count;

ssize_t nwritten;

char *bufp = (char*)buf;

while (nleft > 0)

{

if ((nwritten = write(fd, bufp, nleft)) < 0)

{

if (errno == EINTR)

continue;

return -1;

}

else if (nwritten == 0)

continue;

bufp += nwritten;

nleft -= nwritten;

}

return count;

}

ssize_t recv_peek(int sockfd, void *buf, size_t len)

{

while (1)

{

int ret = recv(sockfd, buf, len, MSG_PEEK);

if (ret == -1 && errno == EINTR)

continue;

return ret;

}

}

ssize_t readline(int sockfd, void *buf, size_t maxline)

{

int ret;

int nread;

char *bufp = buf;

int nleft = maxline;

while (1)

{

ret = recv_peek(sockfd, bufp, nleft);

if (ret < 0)

return ret;

else if (ret == 0)

return ret;

nread = ret;

int i;

for (i=0; i<nread; i++)

{

if (bufp[i] == '\n')

{

ret = readn(sockfd, bufp, i+1);

if (ret != i+1)

exit(EXIT_FAILURE);

return ret;

}

}

if (nread > nleft)

exit(EXIT_FAILURE);

nleft -= nread;

ret = readn(sockfd, bufp, nread);

if (ret != nread)

exit(EXIT_FAILURE);

bufp += nread;

}

return -1;

}

void echo_cli(int sock)

{

/*

char sendbuf[1024] = {0};

char recvbuf[1024] = {0};

while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)

{

writen(sock, sendbuf, strlen(sendbuf));

int ret = readline(sock, recvbuf, sizeof(recvbuf));

if (ret == -1)

ERR_EXIT("readline");

else if (ret == 0)

{

printf("client close\n");

break;

}

fputs(recvbuf, stdout);

memset(sendbuf, 0, sizeof(sendbuf));

memset(recvbuf, 0, sizeof(recvbuf));

}

close(sock);

*/

fd_set rset;

FD_ZERO(&rset);

int nready;

int maxfd;

int fd_stdin = fileno(stdin);

if (fd_stdin > sock)

maxfd = fd_stdin;

else

maxfd = sock;

char sendbuf[1024] = {0};

char recvbuf[1024] = {0};

int stdineof = 0;

while (1)

{

if (stdineof == 0)

FD_SET(fd_stdin, &rset);

FD_SET(sock, &rset);

nready = select(maxfd+1, &rset, NULL, NULL, NULL);

if (nready == -1)

ERR_EXIT("select");

if (nready == 0)

continue;

if (FD_ISSET(sock, &rset))

{

int ret = readline(sock, recvbuf, sizeof(recvbuf));

if (ret == -1)

ERR_EXIT("readline");

else if (ret == 0)

{

printf("server close\n");

break;

}

fputs(recvbuf, stdout);

memset(recvbuf, 0, sizeof(recvbuf));

}

if (FD_ISSET(fd_stdin, &rset))

{

if (fgets(sendbuf, sizeof(sendbuf), stdin) == NULL)

{

stdineof = 1;

/*

close(sock);

sleep(5);

exit(EXIT_FAILURE);

*/

shutdown(sock, SHUT_WR);

}

else

{

writen(sock, sendbuf, strlen(sendbuf));

memset(sendbuf, 0, sizeof(sendbuf));

}

}

}

}

void handle_sigpipe(int sig)

{

printf("recv a sig=%d\n", sig);

}

int main(void)

{

/*

signal(SIGPIPE, handle_sigpipe);

*/

signal(SIGPIPE, SIG_IGN);

int sock;

if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)

ERR_EXIT("socket");

struct sockaddr_in servaddr;

memset(&servaddr, 0, sizeof(servaddr));

servaddr.sin_family = AF_INET;

servaddr.sin_port = htons(5188);

servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

if (connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)

ERR_EXIT("connect");

struct sockaddr_in localaddr;

socklen_t addrlen = sizeof(localaddr);

if (getsockname(sock, (struct sockaddr*)&localaddr, &addrlen) < 0)

ERR_EXIT("getsockname");

printf("ip=%s port=%d\n", inet_ntoa(localaddr.sin_addr), ntohs(localaddr.sin_port));

echo_cli(sock);

return 0;

}

conntest.c

#include <unistd.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <signal.h>

#include <stdlib.h>

#include <stdio.h>

#include <errno.h>

#include <string.h>

#define ERR_EXIT(m) \

do \

{ \

perror(m); \

exit(EXIT_FAILURE); \

} while(0)

int main(void)

{

int count = 0;

while(1)

{

int sock;

if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)

{

sleep(4);

ERR_EXIT("socket");

}

struct sockaddr_in servaddr;

memset(&servaddr, 0, sizeof(servaddr));

servaddr.sin_family = AF_INET;

servaddr.sin_port = htons(5188);

servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

if (connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)

ERR_EXIT("connect");

struct sockaddr_in localaddr;

socklen_t addrlen = sizeof(localaddr);

if (getsockname(sock, (struct sockaddr*)&localaddr, &addrlen) < 0)

ERR_EXIT("getsockname");

printf("ip=%s port=%d\n", inet_ntoa(localaddr.sin_addr), ntohs(localaddr.sin_port));

printf("count = %d\n", ++count);

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐