리눅스 epoll를 이용하여 SMTP 서버를 구현 중입니다만...

sjang의 이미지

epoll를 다룬 예제를 보면 아래와 같은 코드가 있습니다.


struct epoll_event ev, *events;

       for(;;) {
           nfds = epoll_wait(kdpfd, events, maxevents, -1);

           for(n = 0; n < nfds; ++n) {
/***************** 요기 **********************/ 
               if(events[n].data.fd == listener) {
/*******************************************/
                   client = accept(listener, (struct sockaddr *) &local,
                                   &addrlen);
                   if(client < 0){
                       perror("accept");
                       continue;
                   }
                   setnonblocking(client);
                   ev.events = EPOLLIN | EPOLLET;
                   ev.data.fd = client;
                   if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) < 0) {
                       fprintf(stderr, "epoll set insertion error: fd=%d0,
                               client);
                       return -1;
                   }
               }
               else
                   do_use_fd(events[n].data.fd);
           }
       }

여기에서

events[n].data.fd == listener

형태로 이벤트가 발생한 디스크립터에 대해서 data 라는 union 자료구조의 fd 라는 멤버를 이요하여 이벤트가 발생한 디스크립터 값을 알 수 있는거 같습니다.

제가 하려고 하는 것은 SMTP 자료구조를 정의 일정 메모리를 확보하여 할당한 뒤에 큐형식으로 관리하려 합니다. SMTP 접속이 있을 때마다 큐에서 SMTP 자료구조를 하나씩 빼서 할당하는 것이죠.

이 SMTP 자료구조 안에는 fd 값이 있습니다. 위의 events[n].data.fd 를 이용하여 접속을 시작할 때 할당하는 것이죠.

그런데, epoll_wait()를 이용하여 이벤트가 발생한 fd는 바로 알 수가 있는데, 이 fd 를 가진 SMTP 구조체를 찾아야 합니다.

큐에서 빠져나와 할당되어 있는 SMTP 자료구조 중에서 이벤트가 발생한 fd 값을 가진 놈을 찾아야 하는 것이죠. 그래야 메시지 받은 것도 저장하고 기타등등 해야하니까요.

할당된 SMTP 자료구조에서 해당 fd와 같은지 비교하는 작업을 이벤트가 발생한 fd 마다 다 해주어야 한다면 overhead가 꽤 있을 듯 합니다. hash table 같은 것을 쓰면 빠르게 되긴 하겠죠.

질문은... epoll를 쓸 때 이런 식의 접근이 맞는지 궁금해서 글을 남깁니다. epoll.h에 써 있는 epoll_data_t 라는 놈이 왜 union으로 되어 있는지 의미도 잘 모르겠고요...(다른 OS와의 호환때문??)

epoll_wait()의 리턴값이 이벤트가 발생한 fd의 개수인데, 리턴값이 3이라면 예제에서 for 구문을 통해서 차례대로 돌리는 것을 보면 메모리 할당한 epoll_data_t의 구조체가 이벤트가 발생한 것 순으로 차례대로 줄을 세우나 보죠? 그것도 궁금하고요...

hanzo69의 이미지

개발자에 따라 epoll_event 에 fd가 아니라 fd를 감싸고 있는 객체 주소를 넣는 경우, 혹은 인덱스등을 넣게 하기 위해서일 듯 하네요.
저같은 경우 fd에 소켓 디스크립터를 넣지 않고, ptr로 해서 소켓 객체 주소를 넣어 인터페이스로 리스너와, 피어 소켓을 분기없이 처리하게 구현했으니까요.

EPOLL_CTL_ADD를 하실때 fd 멤버에 소켓 디스크립터를 셋팅하지 마시고, ptr 멤버에 그 SMTP 구조체 포인터를 넣으시면 됩니다.

어차피 저 fd는 굳이 유효한 fd로 설정할 필요가 없는놈이니까요.
글쎄.. 근데 정말 왜 저런식으로 했는지는 저도 이해가 안가는..
그냥 포인터 하나면 될텐데... 쩝-_-; 예제도 그렇구..

===============
죄송한데.. 저도 밑에 epoll관련 질문 하나 올렸거든요.. 혹시 아시는 부분이면 답변 좀 부탁드립니다.. 흐미.. 아직 테스트를 안해서..

님ㅎ 즐~

sjang의 이미지

감사합니다.

epoll add 할때 listener 만 fd 값을 셋팅하고

나머지 fd에 대해서는 ptr를 가리키는 smtp 구조체 안에 멤버변수로

셋팅하니 잘 되는군요.

The Future !!!

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.