fifo와 select에 대한 예제..질문입니다.

익명 사용자의 이미지

예제는 Server에서 먼저 readonly로 fifo를 열고, client는 writeonly로
fifo를 열어서 abcde를 client에서 보내고 server에서 이를 읽어들이는
것입니다.

여기서...

Server(sel_s)를 먼저 실행하고, Client(sel_c)를 나중에 실행하는 경우
아무런 PIPE가 끊어졌다는 메시지와 함께 제대로 동작이 되지 않습니다.

반대로 sel_c를 먼저 실행하고 sel_s를 나중에 실행하면...제대로 실행이
되는 군요...도대체 뭐가 잘못 된 거죠?

결국 원하는 것은 sel_s를 먼저 실행해서 read only로 open하고 sel_c를
나중에 실행해서 write하는 건데요...이게 잘 않 됩니다.

프로그램중 어디가 잘 못 된 것인지...

고수님들의 가르침을 부탁드립니다.

-----------sel_s.c-------------------

include
#include
#include
#include
#include
#include
#include

void sig_poll();
void sig_io();
void sig_pipe();

int main()
{
int fd, ret;
char receive[6];
fd_set wset, eset, rset;

signal(SIGPOLL, sig_poll);
signal(SIGAIO, sig_io);
signal(SIGPIPE, sig_pipe);

puts("before open");

if((fd = open("./fifo", O_RDONLY)) < 0) {
perror("open");
exit(1);
}

puts("after open, before select");

FD_ZERO(&wset);
FD_SET(fd, &wset);

FD_ZERO(&eset);
FD_SET(fd, &eset);

FD_ZERO(&rset);
FD_SET(fd, &rset);

ret = select(FD_SETSIZE, &rset, &wset, &eset, NULL);

if(ret < 1)
{
perror("sel_s");
exit(1);
}
puts("after select");

if( FD_ISSET ( fd, &wset))
{
puts("WRITE SET...what?");
}
else if ( FD_ISSET (fd, &eset))
{
puts("I can't read...eset setting!!");
}
else if ( FD_ISSET (fd, &rset))
{
read(fd, receive, 6);
printf("read data is %s!!\n", receive);
}
else
{
puts("I don't know...it!!");
}

}

void sig_poll()
{
puts("haha!!!..IT'S POLL SIGNAL\n");
signal(SIGPOLL, sig_poll);
}

void sig_io()
{
puts("haha!!!..IT'S IO SIGNAL\n");
signal(SIGAIO, sig_io);
}

void sig_pipe()
{
puts("haha!!!..IT'S PIPE SIGNAL\n");
signal(SIGPIPE, sig_pipe);
}

-------------sel_c.c--------------------------------

#include
#include
#include
#include
#include
#include

void sig_poll();
void sig_io();
void sig_pipe();

int main()
{
int fd, ret;
char receive[6];
fd_set wset, rset, eset;

if((fd = open("./fifo", O_WRONLY)) < 0) {
perror("open");
exit(1);
}

puts("after open");
strcpy(receive, "abcde");
puts("after strcpy");

FD_ZERO(&wset);
FD_SET(fd, &wset);

FD_ZERO(&eset);
FD_SET(fd, &eset);

FD_ZERO(&rset);
FD_SET(fd, &rset);

ret = select(FD_SETSIZE, &rset, &wset, &eset, NULL);

if(ret < 1)
{
perror("sel_s");
exit(1);
}
puts("after select");

if( FD_ISSET ( fd, &wset))
{
write(fd, receive, 6);
printf("WRITE SET...OK%s\n", receive);

}
else if ( FD_ISSET (fd, &eset))
{
puts("I can't read...eset setting!!");
}
else if ( FD_ISSET (fd, &rset))
{
printf("read data ....what?");
}
else
{
puts("I don't know...it!!");
}
/*
printf("WRITE DATA...READY\n");
write(fd, receive, 6);
printf("WRITE DATA...OK%s\n", receive);
*/
close(fd);
exit(0);
}

void sig_poll()
{
puts("haha!!!..IT'S POLL SIGNAL\n");
signal(SIGPOLL, sig_poll);
}

void sig_io()
{
puts("haha!!!..IT'S IO SIGNAL\n");
signal(SIGAIO, sig_io);
}

void sig_pipe()
{
puts("haha!!!..IT'S PIPE SIGNAL\n");
signal(SIGPIPE, sig_pipe);
}

------------여기까지----------------

익명 사용자의 이미지

소스가 간단하면 에러도 간단하게 보이죠. ^^;
일단 소스중에 잘못된(?) 곳은 sel_s.c에서 fifo를 read only로 여는 부분입니다.
소스에서 fifo라는 파일이 없다면 에러를 출력하라고 하는 부분이죠.
이유는 sel_s는 sel_c가 먼저 실행되지 않는다면 그냥 에러를 출력하고 끝나죠.
현재 생각하신 로직과는 맞지 않는 부분이죠.
바꾸는 방법은 의외로 간단합니다.
while이나 do 같은 루프를 이용해야겠죠.
그리고 에러가나면 그걸 단순하게 처리하면 안됩니다.
fifo파일이 없다는 것은 Client가 아직 실행되지 않는다는 소리고 따라서 그건 에러가
아니라는 소리겠죠.
약간 효율성은 떨어지지만...

while (1) {
...
if ((fd = open ("./fifo", O_RDONLY)) > 0) {
puts ("after open, before select");

FD_ZERO(&wset);
FD_SET(fd, &wset);

...
} else {
sleep (3);
}
}

이런 식으로 해준다면 연결이 없을 때는 3초가 기다리다가 다시 연결점을 찾겠죠.
앞에도 말했듯이 효율은 떨어집니다.
아~ 그리고 생각하실 것은 server는 연결을 무한정 기다려야 한다는 점입니다.
만일 하나의 연결만 찾고 하나의 행동만 하고 끝나면 그건 서버로서의 역할이 아닐
수도 있죠. ^^;

익명 사용자의 이미지

sel_s에 대한 bug 수정 프로그램입니다.

단 한계점은 동시에 여러개의 client program을 돌릴 수 없다는 게 한계
입니다.

가능하다면 그런 한계점을 극복할 수 있는 다음 버전의 프로그램을 올려
보도록 노력하겠습니다.

개선된 sel_s.c

--------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include

void sig_poll();
void sig_io();
void sig_pipe();

int main()
{
int fd, ret, i= 0, j;
char receive[6];
fd_set wset, eset, rset;

signal(SIGPOLL, sig_poll);
signal(SIGAIO, sig_io);
signal(SIGPIPE, sig_pipe);

puts("before open");

while(1)
{
if((fd = open("./fifo", O_RDONLY)) < 0) {
perror("open");
exit(1);
}

puts("after open, before select");
printf("fd num is %d", fd);

FD_ZERO(&rset);
FD_SET(fd, &rset);

ret = select(FD_SETSIZE, &rset, NULL, NULL, NULL);

if(ret < 1)
{
perror("sel_s");
exit(1);
}
puts("after select");

if ( FD_ISSET (fd, &rset))
{
if( (ret = read(fd, receive, 6)) == 0)
{
puts("write side is dead");
FD_CLR(fd, &rset);
continue;
}
printf("read data is %s!!\n", receive);
}

close(fd);
}

}

void sig_poll()
{
puts("haha!!!..IT'S POLL SIGNAL\n");
signal(SIGPOLL, sig_poll);
}

void sig_io()
{
puts("haha!!!..IT'S IO SIGNAL\n");
signal(SIGAIO, sig_io);
}

void sig_pipe()
{
puts("haha!!!..IT'S PIPE SIGNAL\n");
signal(SIGPIPE, sig_pipe);
}

-------------여기까지-------------------------------------

댓글 달기

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