오늘 my httpd 의 연결 처리 모드 를 select 에서 epoll 로 바 꿉 니 다.
poll 의 실행 은 세 부분 으로 나 뉜 다. 1. 사용자 가 들 어 온 pollfd 배열 을 커 널 공간 으로 복사 합 니 다. 복사 작업 은 배열 의 길이 와 관련 되 기 때문에 시간 적 으로 O (n) 작업 입 니 다. 각 파일 설명자 가 대응 하 는 장치 의 상 태 를 조회 합 니 다. 이 장치 가 준비 되 지 않 으 면 이 장치 의 대기 열 에 하 나 를 추가 하고 다음 장치 의 상 태 를 계속 조회 합 니 다.모든 장 치 를 조회 한 후 장치 가 준비 되 지 않 으 면 현재 프로 세 스 를 걸 고 기 다 려 야 합 니 다. 장치 가 준비 되 거나 시간 이 초 과 될 때 까지 기 다 려 야 합 니 다.장치 가 준 비 된 후에 프로 세 스 가 계속 실행 되 라 는 통 지 를 받 았 습 니 다. 이 때 모든 장 치 를 다시 옮 겨 다 니 며 준 비 된 장 치 를 찾 습 니 다.이 단 계 는 모든 장 치 를 두 번 이나 옮 겨 다 니 기 때문에 시간 복잡 도 역시 O (n) 이 고 이 안 에는 대기 시간 이 포함 되 지 않 습 니 다. 3. 획득 한 데 이 터 를 사용자 공간 으로 전송 하고 메모리 방출 과 대기 열 박리 등 사후 작업 을 수행 하 며 사용자 공간 에 데 이 터 를 복사 하 는 것 과 대기 열 박리 등 작업 을 하 는 시간 복잡 도 는 O (n) 입 니 다.epoll 에 사용 되 는 모든 함 수 는 헤더 파일 sys / epoll. h 에서 설명 합 니 다. 아래 에 사용 되 는 데이터 구조 와 함 수 를 간략하게 설명 합 니 다. 사용 되 는 데이터 구조 typedef union epolldata { void *ptr; int fd; __uint32_t u32; __uint64_t u64; } epoll_data_t; struct epoll_event { __uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */ }; 구조 체 epoll event 는 관심 있 는 이벤트 와 리 턴 을 등록 하 는 데 사 용 됩 니 다. 이 중 epoll data 연합 체 는 트리거 이벤트 의 한 파일 설명자 와 관련 된 데 이 터 를 저장 하 는 데 사 용 됩 니 다. 예 를 들 어 하나의 client 가 서버 에 연결 되 어 있 으 며, 서버 는 accept 함 수 를 호출 하여 이 client 에 대응 하 는 socket 파일 설명 자 를 얻 을 수 있 습 니 다. 이 파일 설명 자 를 사용 할 수 있 습 니 다.이 파일 설명자 에서 다음 읽 기와 쓰기 동작 을 할 수 있 도록 epoll data 의 fd 필드 에 부 여 됩 니 다. epoll event 구조 체 의 events 필드 는 관심 을 표시 합 니 다.
출처 장 심 붕 의 자바 아이 블 로그
학습 노트
http://zsp.iteye.com/blog/146850
- - 주: 위의 내용 은 모두 발췌 문 입 니 다. -
이전 select 모드 의 코드
/* server.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include "wrap.h"
#include "httpprocesser.h"
#define MAXLINE 800
#define SERV_PORT 7080
#define BACKLOG 200
int main(int argc, char **argv)
{
int i, maxi, maxfd, listenfd, connfd, sockfd;
int nready, client[FD_SETSIZE];
ssize_t n;
fd_set rset, allset;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
socklen_t cliaddr_len;
struct sockaddr_in cliaddr, servaddr;
listenfd = my_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);
my_bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
my_listen(listenfd, BACKLOG);
maxfd = listenfd; /* initialize */
maxi = -1; /* index into client[] array */
for (i = 0; i < FD_SETSIZE; i++)
client[i] = -1; /* -1 indicates available entry */
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
for ( ; ; ) {
rset = allset; /* structure assignment */
nready = select(maxfd+1, &rset, NULL, NULL, NULL);
if (nready < 0)
perr_exit("select error");
if (FD_ISSET(listenfd, &rset)) { /* new client connection */
cliaddr_len = sizeof(cliaddr);
connfd = my_accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
printf("received from %s at PORT %d
",
inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
ntohs(cliaddr.sin_port));
for (i = 0; i < FD_SETSIZE; i++)
if (client[i] < 0) {
client[i] = connfd; /* save descriptor */
break;
}
if (i == FD_SETSIZE) {
fputs("too many clients
", stderr);
exit(1);
}
FD_SET(connfd, &allset); /* add new descriptor to set */
if (connfd > maxfd)
maxfd = connfd; /* for select */
if (i > maxi)
maxi = i; /* max index in client[] array */
if (--nready == 0)
continue; /* no more readable descriptors */
}
for (i = 0; i <= maxi; i++) { /* check all clients for data */
if ( (sockfd = client[i]) < 0)
continue;
if (FD_ISSET(sockfd, &rset)) {
if ( (n = my_read(sockfd, buf, MAXLINE)) > 0) {
struct http_msg msg;
parse_msg(buf, &msg);
printf("%s
", msg.response);
my_write(sockfd, buf, n);
}
/* connection closed by client */
my_close(sockfd);
FD_CLR(sockfd, &allset);
client[i] = -1;
if (--nready == 0)
break; /* no more readable descriptors */
}
}
}
}
현재 사용 하고 있 는 epoll 모드 의 코드
이 부분의 코드 는
http://blog.csdn.net/mote_li/archive/2004/12/08/209450.aspx
pthread 라 이브 러 리 를 기반 으로 한 작업 대기 열 방식 의 스 레 드 풀 도 추가 되 었 습 니 다.#ifndef __myhttpd_h
#define __myhttpd_h
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <strings.h>
#include <pthread.h>
#include "wrap.h"
#include "task.h"
#define OPEN_MAX 100
#define LISTENQ 20
#define INFTIM 1000
#define LOCAL_IP "127.0.0.1" /* */
#define SERV_PORT 5555
extern pthread_mutex_t mutex; /* */
extern pthread_cond_t cond1; /* */
extern struct task *readhead ,
*readtail ,
*writehead ;
extern struct epoll_event ev, events[20];
extern int epfd;
void setnonblocking(int sock)
{
int opts;
opts = fcntl(sock, F_GETFL);
if(opts<0)
{
perror("fcntl(sock,GETFL)");
exit(1); /* , , */
}
if(fcntl(sock, F_SETFL, opts | O_NONBLOCK)<0)
{
perror("fcntl(sock,SETFL,opts)");
exit(1);
}
}
int main()
{
int i, maxi, listenfd, connfd, sockfd, nfds;
socklen_t clilen;
pthread_t tid1,tid2;
struct task *new_task=NULL;
struct user_data *rdata=NULL;
readhead = readtail = writehead = NULL;
/* initialize the thread pool */
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond1, NULL);
/* , , . ! */
pthread_create(&tid1, NULL, readtask, NULL);
pthread_create(&tid2, NULL, readtask, NULL);
/* accept epoll
*
*
Create a new epoll file descriptor by requesting the kernel allocate an event backing store dimensioned
[n. , , ( ), ( ), ] for size descriptors.
The size is not the maximum size of the backing store but just a hint to the kernel about
how to dimension internal structures.
The returned file descriptor will be used for all the subsequent calls to the epoll interface.
The file descriptor returned by epoll_create must be closed by using POSIX::close.
When successful, epoll_create returns a positive integer identifying the descriptor. When an error occurs,
epoll_create returns -1 and errno is set appropriately.
*
*/
epfd = epoll_create(256);
struct sockaddr_in clientaddr;
struct sockaddr_in serveraddr;
listenfd = my_socket(AF_INET, SOCK_STREAM, 0);
// socket
setnonblocking(listenfd);
//
ev.data.fd = listenfd;
//
ev.events = EPOLLIN | EPOLLET;
/* epoll
Control an epoll descriptor, $epfd, by requesting the operation op be performed on the target file descriptor, fd.
$epfd is an epoll descriptor returned from epoll_create.
$op is one of EPOLL_CTL_ADD, EPOLL_CTL_MOD or EPOLL_CTL_DEL.
$fd is the file desciptor to be watched.
$eventmask is a bitmask of events defined by EPOLLIN, EPOLLOUT, etc.
When successful, epoll_ctl returns 0. When an error occurs, epoll_ctl returns -1 and errno is set appropriately.
*/
epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
char *local_addr = LOCAL_IP;
inet_aton(local_addr, &(serveraddr.sin_addr));
serveraddr.sin_port = htons(SERV_PORT);
my_bind(listenfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
my_listen(listenfd, LISTENQ);
maxi = 0;
for ( ; ; )
{
/* epoll
Wait for events on the epoll file descriptor $epfd.
$epfd is an epoll descriptor returned from epoll_create.
$maxevents is an integer specifying the maximum number of events to be returned.
$timeout is a timeout, in milliseconds
When successful, epoll_wait returns a reference to an array of events. Each event is a two element array,
the first element being the file descriptor which triggered the event,
and the second is the mask of event types triggered.
For example, if epoll_wait returned the following data structure:
*/
nfds = epoll_wait(epfd, events, 20, 500);
//
for(i = 0; i < nfds; ++i)
{
if(events[i].data.fd == listenfd)
{
connfd = my_accept(listenfd, (struct sockaddr *)&clientaddr, &clilen);
if(connfd < 0)
{
perror("connfd<0");
exit(1);
}
setnonblocking(connfd);
char *str = inet_ntoa(clientaddr.sin_addr);
printf("connect_from >> %s
", str);
ev.data.fd = connfd; //
ev.events = EPOLLIN | EPOLLET; //
// ev
epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
}
else if (events[i].events & EPOLLIN)
{
printf("reading!
");
if ((sockfd = events[i].data.fd) < 0)
continue;
new_task = (struct task *)malloc(sizeof(struct task));
new_task->fd = sockfd;
new_task->next = NULL;
pthread_mutex_lock(&mutex); //
if(readhead == NULL)
{
readhead = new_task;
readtail = new_task;
}
else
{
readtail->next = new_task;
readtail = new_task;
}
// cond1
pthread_cond_broadcast(&cond1);
pthread_mutex_unlock(&mutex);
}
else if (events[i].events & EPOLLOUT)
{
rdata = (struct user_data *)events[i].data.ptr;
sockfd = rdata->fd;
printf("thread.%u Write data fd.%d len.%d data.%s
"
, (uint32_t)pthread_self(), sockfd, rdata->n_size, rdata->line);
my_write(sockfd, rdata->line, rdata->n_size);
my_close(sockfd);
free(rdata);
ev.data.fd = sockfd; //
ev.events = EPOLLIN | EPOLLET; //
// sockfd EPOLIN
epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
}
}
}
}
#endif
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Exception in thread main java.lang. NoClassDefFoundError 오류 해결 방법즉,/home/hadoop/jarfile) 시스템은 Hello World 패키지 아래의class라는 클래스 파일을 실행하고 있다고 오인하여 시스템의 CLASSPATH 아래 (일반적으로 현재 디렉터리를 포함) Hell...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.