열려져 있던 소켓이 "close"되었는지..아닌지 알수 있

shean0의 이미지

지금 폰과 통신하는프로그램을 작성중인데요..
서버에서 close하기전에 "폰쪽에서는 "close되었다구 하는데요..

서버에서 소켓넘버를 가지고 체크하는 방법이 없을까요??
아니면..다른 방법이라두..일단 accept된 소켓 번호를 int값을 가지고 있구.
close(sock_num); 하면.
.. sock_num==>NULL 일 것이라 생각했는데..
아니더군요..

음..어떤 방법이 있느지??

버그소년의 이미지

fcntl ()이나 setsockopt ()등으로 해당 소켓을 NONBLOCK으로

만든후에 recv ()를 해 보면 될것 같네요..

꼭 NONBLOCK뿐아니라 소켓옵션에 recv 타임아웃을 설정해도 될테고..

recv ()의 리턴값이 -1이면 close 된것이고 0이면 살아있지만 타임아웃

걸린거고, 0 이상이면 데이터를 수신한게 되겠죠..

가끔은 밥을 굶어도 살 수 있다.

june8th의 이미지

sockfd값은 그냥 int값일뿐, 그걸로는 close여부를 알수 없지요.
그걸로 어떤 작업을 하다가 에러 나면 리턴값과 에러코드 보구 처리하곤 합니다.

보통 주된 close위치는, 읽다가 에러날 때 소켓을 닫는데요..
(non-block일땐 errno이 EAGAIN등이 아닐때 close)

제가 질문의 의도에 맞춰 제대로 답변을 하는건지 아리송 하네요.. :-P

shean0의 이미지

예를 들면 이런 소켓 소스에서요

main()
{  
 listen(); 
   (void)signal(SIGCHLD, ignoreThisSignal);      
  while(1) 
 { 
   accept(); 
    fork();  
    if(자식) ==>{ call_child_main(sok_num);
                        /*여기 1 에 서 close(sok_num)*/ exit(0); } 
  } 
}

call_child_main(sok_num) 
{ 
  while(flag)
  {
    recv_data(); 
    make_data(); 
    send_data(); 
  }
   /*여기 2*/
    return TRUE; /* OK */ 
}

위의 소스 /*여기*/ 에서 close되었는지 여부를 알수 있는 방법은 없을까요?
답변중에 fctl,setsockopt를 사용하면 된다고 하셔서.지금 보고 있는데요..
예제가 없더서.... 그런데..제가 보고 있는 자료중에
이것을 사용할 려면 , listen() 호출전에 사용하라고 언급되어 있더군요.
그러면..이후 동작하는 모든 read,write가 non-blocking으로 되는것 아닌가요?

그러면 안 되는데요.. read에서는 blocking이 되어야 하는데..

제가 잘 못 알고 있는것인지..그냥 사용하면 되는데..괜한 우려인가요??

/**/여기2 에서는 close(sok_num)하면 return 값이 ==>0 : 정상종료
그런데 여기1 에서 close(sok_num)하면(물론 여기1 에서 close 안 했구요) return 값이 -1 : 에러로 나오는 현상은 무엇때문일까요???

언제나 즐프를 꿈꾸며~

dotri의 이미지

select() 함수라는 함수가 있죠. 해당 소켓에 쓰기가 가능한지, 읽기가 가능한지, 에러인지 아닌지를 감시해주는 함수인데.. 쓰일만할지?

송지석의 이미지

저번에 질문 하셨던 분 같은데.. 음.

역시나 아직 회사가 아닌관계로 자세한 설명은 불가능하군요..

일단 이렇게 하면 알아보실 수 있을겁니다.

저는 쓰레드를 돌려서 소켓에서 받는 작업을 했는데요.

select를 쓰시면 질문하신 구현이 될 것입니다.

일단 경험적으로 제가 아는 것이..
소켓에서 recv했을 때 정상적으로 받은 것으로 나오고 받은 길이가 0이면 보통 연결이 (정상) 종료된 경우더군요.(이부분은 제가 틀렸으면 지적해주세요. 윈도에선 확실히 그랬던 것 같고...)

select는 리눅스 기초 프로그래밍 책에 잘 나와있을 것 같네요 소켓 통신쪽에..

select문에 read, write, error FD체크 부분이 있잖아요 거기에 알맞은 소켓을 넣어두고(이부분은 책 찾아보세욥. 아니면 kldp에 한글로 소켓 프로그래밍 부분이 있습니다. (Beej의 소켓 프로그래밍 하우투였나..))
또한 timeout값도 넣어두세요. 1초, 0.2초 맘대로...
그리고 while 문으로 루프 돌립니다. (아 물론 while이 아니어도 루프를 돌리실 수 있습니다 쩝..)
select의 리턴값이 0이 아니면 에러이거나 타임아웃이고
read,write, error 셋중 어떤 이벤트가 떠서 select문에서 빠져나왔는지 체크하시고 (FD_SET(read_fd)였나..)

read였다면 읽어보시고 길이도 체크해보시고, error였다면 에러체크 해보시고 연결 끊으시고요.. 이렇게 받는 쓰레드or 프로세스에서 처리하시면 될 것 같네요.

펑키의 이미지

제 생각에도 전에 질문 하셨던분 같네요. 혹시 제게 이메일 보내주셨던분 맞나요.? 제가 답장 할려고 해도 편지가 되돌아 와서 편지를 못보내 드렸습니다. 하여간 여기서 다시 뵈니 반갑습니다.

서버쪽에서 클라이언트의 통신 상태를 체크 하기에는 SELECT가 "와따" 입니다. 먼저 SELECT를 사용하기 이전에 NON-BLOCK 모드로 들어 가시고 SELECT를 사용하시고 RECV쪽에서 감지 하시면 됩니다. 즉, RECV는 정상 리턴일때 읽은 바이트 만큼 리턴을 하지만 RECV() <= 0 일 경우에는 모두 에러입니다. 이중 중요 한것은 0 인데 바로 이부분이 접속이 정상적으로 끊어진것입니다.

그리고 한가지 주의 하실점은 TCP/IP통신에서는 전달은 보증이 되지만 언제 전달이 될지는 보증이 되지 않습니다. 따라서 세가지 부분을 만들어 놓으셔야만 되는데

1. SELECT에서 NON-BLOCK 모드로 통신 하게 설정 fcntl 등...
2. 원하는 시간 만큼 타임아웃을 SELECT에 설정
3. recv에서 내가 읽을 바이트수 만큼 읽고서 리턴하게 설정(while 등으로)

이정도 입니다.

쓰레드나 PORK는 제가 사용하지 않아서 그쪽은 잘 모르겠습니다.

lol

shean0 wrote:
지금 폰과 통신하는프로그램을 작성중인데요..
서버에서 close하기전에 "폰쪽에서는 "close되었다구 하는데요..

서버에서 소켓넘버를 가지고 체크하는 방법이 없을까요??
아니면..다른 방법이라두..일단 accept된 소켓 번호를 int값을 가지고 있구.
close(sock_num); 하면.
.. sock_num==>NULL 일 것이라 생각했는데..
아니더군요..

음..어떤 방법이 있느지??

송지석의 이미지

제 프로젝트에서 쓰던 거라 바로 적용되시진 않을 지 모르지만 제 코드를 주석 달아서 올립니다.

말씀 드렸다시피 저는 쓰레드로 돌렸습니다.

void *Thread(void *args)
{
    struct  timeval timeout;
    int     result;
    int     sock_max;
    fd_set e_set;
    char buf[MAX_LEN];


    FD_ZERO((fd_set *)&R_Set);   // fd를 초기화 합니다. R_Set은 전역변수.. fd_set R_Set
    if(Sock_Stream!=-1)
        FD_SET(Sock,&R_Set);  // stream 소켓을 R_Set에 넣습니다. Sock: 전역변수.. 소켓 번홉니당
    FD_ZERO((fd_set *)&e_set);
    FD_SET(Sock, &e_set);

    while(!Thread_Exit) {
        timeout.tv_sec=0;
        timeout.tv_usec=300000;  ///wait 300ms
        if(Sock!=-1)
            FD_SET(Sock, &e_set);
        if(Sock_Packet!=-1)
            FD_SET(Sock_Packet, &e_set);
        sock_max = MAX (Sock, Sock_Packet);
        result = select ( sock_max+1 , (fd_set *)&R_Set, NULL, &e_set, &timeout); // rx, error이벤트가 뜨거나 타임아웃 될 때 까지 기다립니다.
        if(result==-1)
            perror("\\\\\\\\\\\\\\\\\\\\\\[CommT]select");
        if(FD_ISSET(Sock, &e_set))
            fprintf(stderr, "Sock error\n");
        if(FD_ISSET(Sock_Packet, &e_set))
            fprintf(stderr, "Sock_Packet error\n");
        if (FD_ISSET(Sock, &R_Set)) /// data comes
        {
            len = recv(Sock, buf, STREAM_LEN,0);
            if (len<=0) ///error, connection lost
            {
#ifdef DEBUG
                perror("Error! recv stream");
#endif
                ErrorNo = ERROR_CONNECTION_LOST;
                ErrorFlag= ERROR_OCCURED;
                tHardDisconnect();
            }
            ...

또 받는 메시지의 길이가 정해져있을 때는

    rcv_len= recv(s, resp_buf, RESP_LEN, MSG_WAITALL);// recv response
    if (rcv_len==-1)
    {
#ifdef DEBUG
        perror("recv");
        fprintf(stderr, "errno=%d\n", errno);
#endif
        ReqErrNo=  REQ_ERR_CONNECTION_ERROR;
        return REQ_ERR_CONNECTION_ERROR;
    }

이렇게 MSG_WAITALL로 받으시고 리탄값이 -1일때 연결 에러로 처리하시면 비정상적인 종료를 처리하실 수 있습니다.

그런데 써놓고 보니 가물가물 한 것이.. 어제 쓴 것 처럼 recv의 리턴값이 0이면 연결 종료 된 것인지 기억이 안나네요.. 혹시 아시는 분 답변좀 해주세요..

Quote:
MSG_WAITALL
이 플래그는 완전한 요구가 만족될때까지 작동을
블럭킹하도록 요구한다. 그러나, 만일 신호가
발생하고, 에러나 단절이 발생하거나 받은 다음
데이터가 전에 반환된 데이터와 다른 타입이라면
호출은 여전히 반환된다.

맨페이지에는 WAITALL의 경우는 연결이 끊어져도 리턴하네요. 아마 이때는 길이가 예상했던 것보다 짧을테니 길이체크도 하셔야 되겠습니다.

댓글 달기

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