epoll non blocking 상태에서 sendfile 사용하기

enjoylife의 이미지

void set_nonblocking(int fd)
{
    int opts;
    opts=fcntl(fd, F_GETFL);
    if (opts < 0)
    {
        perror("fcntl failed\n");
        return;
    }
    opts = opts | O_NONBLOCK;
    if(fcntl(fd, F_SETFL, opts) < 0)
    {
        perror("fcntl failed\n");
        return;
    }
    return;
}
 
... 중략 ...
    ev.events = EPOLLIN;
    ev.data.fd = server_fd;
    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev);
    while (1)
    {
        num_fd = epoll_wait(epoll_fd, events, MAXEVENTS, 500);
        for (i=0; i<num_fd; i++)
        {
            if(events[i].data.fd == server_fd)
            {
                client_fd = accept(server_fd, (struct sockaddr *) &client_addr, &len);
                // set_nonblocking(client_fd);
                ev.data.fd = client_fd;
                ev.events = EPOLLIN;
                epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev);
                printf("%d user connect ...\n", ev.data.fd);
            }
            else if(events[i].events & EPOLLIN)
            {
                client_fd = events[i].data.fd;
                ev.data.fd = client_fd;
                ev.events = EPOLLOUT;
                epoll_ctl(epoll_fd, EPOLL_CTL_MOD, client_fd, &ev);
                printf("recv ...\n");
                recv(client_fd, buf, 512, 0);
                printf("%s", buf);
            }
            else if(events[i].events & EPOLLOUT)
            {
                char sendmsg[1024];
                ssize_t offset = 0;
                struct stat stat_buf;
 
                int len;
                char buf[1024];
                int fd = open("a.tar.gz", O_RDONLY);
                if (fd == -1) {
                    fprintf(stderr, "unable to open  %s\n", strerror(errno));
                    exit(1);
                }
                fstat(fd, &stat_buf);
                client_fd = events[i].data.fd;
                sprintf(sendmsg, "HTTP/1.1 200 OK\r\ncontent-type: application/x-octetstream\r\ncontent-disposition: attachment; filename=\"a.tar.gz\"\r\ncontent-length: %zd\r\n\r\n", stat_buf.st_size);
                send(client_fd, sendmsg, strlen(sendmsg), 0);
                /*int opts;
                opts=fcntl(fd, F_GETFL);
                opts = opts | O_NONBLOCK;
                fcntl(fd, F_SETFL, opts);
                fcntl(fd, F_SETFD, FD_CLOEXEC);*/
                ret = sendfile (client_fd, fd, &offset, stat_buf.st_size);
                ev.data.fd = client_fd;
                epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, &ev);
                close(fd);
                close(client_fd);
                printf("send ... size = [%d]\n", ret);
            }
        }
    }

epoll을 사용해서 sendfile로 파일 전송을 하려고 합니다.

웹 브라우저로 접속을 하면 다운로드가 시작이 됩니다.

set_nonblocking 설정을 안하면 block 상태에서는 파일이 정상적으로 다운로드가 됩니다.

문제는 set_nonblocking로 non block으로 변경해서 다운로드를 하면 다운로드 전부 다 되는게

아니고 100kb 이하에서 다운로드가 완료가 됩니다. (용량은 매번 조금씩 다릅니다.)

제가 궁금한건 non block상태에서 sendfile을 이용해서 파일 전송을 하고 싶은데 잘못된 점이나

빠진 부분이 있는지 궁금합니다.

setsockopt - TCP_CORK와 open한 파일을 non block으로 설정도 해보았으나 동일합니다.

chunsj의 이미지

논 블러킹 상황이면 자기가 보낼 수 있는 만큼 - 일어들인 양이 적든, 보낼 수 있는 양이 적든 - 만 보내고 다시 리턴이 됩니다.
따라서 얼마나 보냈는지를 보고 다시 재시도롤 하는 식으로 해서 계속 보내야 됩니다.

블러킹이면 보내지는 이유는 지정한대로 다 보낼때 까지 리턴을 하지 않아서 그렇죠.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.