unp의 tcpservpoll01.c 소스 중에서 maxi 값을 왜 감소 안 시키

익명 사용자의 이미지

poll의 장점이라면 select와는 달리 접속양(?)에 따라서 적절히 maxi를
조절해서 오버헤드를 감소시키는 것으로 알고 있습니다.

그래서, 소스를 봐서 접속함에 따라서 maxi를 증가시키는데요.

왜 마지막의 client의 접속을 끊을 때 maxi의 값을 감소시키지 않는지
이해가 되지 않네요. (정확히는 if (maxi == i) maxi--; 정도가 되겠군요.)

감소시켜서는 안 되는 특별한 이유가 있는 것인지 알고 싶습니다.

이하는 소스입니다.



/* include fig01 */
#include "unp.h"
#include /* for OPEN_MAX */

int
main(int argc, char **argv)
{
int i, maxi, listenfd, connfd, sockfd;
int nready;
ssize_t n;
char line[MAXLINE];
socklen_t clilen;
struct pollfd client[OPEN_MAX];
struct sockaddr_in cliaddr, servaddr;

listenfd = 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);

Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));

Listen(listenfd, LISTENQ);

client[0].fd = listenfd;
client[0].events = POLLRDNORM;
for (i = 1; i < OPEN_MAX; i++)
client[i].fd = -1; /* -1 indicates available entry */
maxi = 0; /* max index into client[] array */
/* end fig01 */

/* include fig02 */
for ( ; ; ) {
nready = Poll(client, maxi+1, INFTIM);

if (client[0].revents & POLLRDNORM) { /* new client connection */
clilen = sizeof(cliaddr);
connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);
#ifdef NOTDEF
printf("new client %s\n", Sock_ntop((SA *) &cliaddr, clilen));
#endif

for (i = 1; i < OPEN_MAX; i++)
if (client[i].fd < 0) {
client[i].fd = connfd; /* save descriptor */
break;
}
if (i == OPEN_MAX)
err_quit("too many clients");

client[i].events = POLLRDNORM;
if (i > maxi)
maxi = i; /* max index in client[] array */

if (--nready <= 0)
continue; /* no more readable descriptors */
}

for (i = 1; i <= maxi; i++) { /* check all clients for data */
if ( (sockfd = client[i].fd) < 0)
continue;
if (client[i].revents & (POLLRDNORM | POLLERR)) {
if ( (n = readline(sockfd, line, MAXLINE)) < 0) {
if (errno == ECONNRESET) {
/*4connection reset by client */
#ifdef NOTDEF
printf("client[%d] aborted connection\n", i);
#endif
Close(sockfd);
client[i].fd = -1;
} else
err_sys("readline error");
} else if (n == 0) {
/*4connection closed by client */
#ifdef NOTDEF
printf("client[%d] closed connection\n", i);
#endif
Close(sockfd);
client[i].fd = -1;
} else
Writen(sockfd, line, n);

if (--nready <= 0)
break; /* no more readable descriptors */
}
}
}
}
/* end fig02 */

익명 사용자의 이미지

poll이 뭔지는 잘 모르지만 소스를 보니 그렇게 해야만 하겠네요.

만일 말씀하신대로 maxi--; 로 한다면 마지막 접속된 client의 소켓을 찾지
못하는 경우가 발생하겠죠.
한번 분석을 해보면...

client [0], client [1], client [2]에 접속이 되어있고 이때 maxi는 3이
되겠죠.
그러면 client [0]가 빠져나가면 maxi--;가 될것이고 maxi는 2가 되면
결국 client [0], client [1]만 검사하는 결과를 낳겠죠.
client [0]는 이미 접속을 끊었으니 check안할 것이면 maxi는 2이니까
client [2]도 check안하고 결국은 client [1]만 check를 하겠네요.
만일 maxi--;를 해주고 싶다면 현재 접속을 해제하는 번호에 마지막번호를
이전 시키고 maxi를 감소시키면 되겠죠. 즉,
client [0] = client [2] 를 해주고 maxi--;를 해주면 문제가 없겠네요.
하지만 저런형태로의 프로그램은 해본적이 없으니 잘된다고는 말할 수
없겠네요. ^^;

익명 사용자의 이미지

일단
poll의 장점이라면 select와는 달리 접속양(?)에 따라서 적절히 maxi를
조절해서 오버헤드를 감소시키는 것으로 알고 있습니다.
여기에서 잘못된점을 지적하고 싶군요.
일반적으로 poll과 select사이에는 큰 차이가 없습니다.
우리가 알고 있는 linux는 select 하부에 poll call 한다고 합니다.

그리고 source를 보니 사용상의 문제가 많을 것 같군요.
먼저 Poll의 내용을 모르기에 정확하게 답변을 주기 힘들지만
스티븐 아저씨(network program)의 스타일을 많이 닮았기에 거의 단정적으로
말한겁니다.

현재의 관리방법으로는 poll의 기능을 십분 활용하는 것이 불가능합니다.

이유는 Poll..에서 만약에 중간에 close된 socket이 존재하게 되면
poll은 Error를 리턴(Bad File Describter)하게될 것이고 이렇게 되면
프로그램은 다시 error로 진행하는 악 순환을 돌게 되기에 시스템은
100% 사용하면서 원활한 작업처리에 지장을 받게 되겠죠.
이는 의도하지 않은 바이기에 곤란한 경우를 당하겠죠.

>> 해결책 1 <<
1. Poll에들어가는 첫째인자를 재구성(유효 SD(Socket Desc))한다.
2. poll할 Count도 재계산하여 그결과를 사용해야 합니다.
3. 이렇게 재구성된 것과 실재 사용된 idx를 사용하여 적절한 조치를 취한다.

>> 해결책 2 <<
Socket 관련 pipe가 닫혔을때 client의 위치를 확인하고 뒤의 sd를 앞으로
당긴다. 이때 maxi값을 감소시킨다.

>> 공통적인 문재점 <<
client[0]에 listen socket이 들어 있는데 이 sd에 에러가 발생하면
프로그램은 더 이상 동작할 의미가 없는데 여기에 대해서도 고민을
많이 해야겠네요. 가장 단순한 것은 exit(1)을 Call하는 것이지만,
다른 대안도 존재 할 듯 합니다. 즉 listen port를 잃었을때 조치 방법이
필요하다는 겁니다.

너무 길게 쓴것 같네요....
이해가 될런지.....

댓글 달기

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