소켓의 상태를 알아보는 방법은?

익명 사용자의 이미지

소켓의 상태가 유효한지 알아보는 방법이 없을까요?

서버와 접속을 해서 통신을 수행중에
혹 있을 천재지변(?)으로 인하여 서버 또는 클라이언트의 접속이 끊겼는데
다른 쪽에서 그걸 전달을 못받았을때

'어 통신해~~ 괜찮아' 혹은 '야~ 지금보니까 끊겼다~~' 뭐 이런걸 알아
낼수 있는 방법이 없을까요?

처음에 셀렉트를 생각을 해봤는데....
만약 셀렉트 함수를 써서 특정 소켓에서 데이터를 송,수신하고 있는데...
갑자기 끊겼다면 recv가 잡고 블럭킹하고 있게 될것이고...
그래서 recv하기 바로직전 정말로 유효한가를 알고 볼려고 하거덩요...

여러 고수님들의 도움 바랍니다.

익명 사용자의 이미지

프로그래밍으로 해결할려고 하시는 건가요? 음...

그건 좀 생각 해 봐야 겠고, 아시다시피 아래와 같이 해보시면

쉽게 아실 수 있을껍니다. 쩝~

일단 프로세스 ID를 알아낸다. 어떻게 하시는지 아시겠죠? ps -ef

프로세스 디렉토리로 이동한다.(예로 프로세스 ID가 6700이라 가정함)

cd /proc/6700/fd/

ls -al 하시면 열려 있는 소켓 넘버가 보이실 껍니다.

쉘상태에서 소켓 넘버로 데이터를 넣어보심 아실 수 있을꺼 같은데...

음... 님의 질문의 의도를 제대로 파악 하고 답변 하는건지

모르겠네요. 지송~~! ㅡ,.ㅡ;

익명 사용자의 이미지

논블럭킹 소켓 + select 를 쓰시는 건 어떠신지...

그리고 소켓이 끊기면... 일단 recv 는 0을 리턴합니다.

별문제 없을듯 합니다. 그럼 고운 하루...

익명 사용자의 이미지

질문하신 분이 1가지 오해하고 있습니다.
select()와 함께 사용하는데
왜 recv()가 데이터가 없다고 blocking을 하죠?
select()가 readfd에 대해서 언제 리턴을 하는지를 다시 한번 생각해 보세요.
데이터가 왔기 때문에 리턴을 한 겁니다.
데이터가 왔기 때문에 그래서 recv()를 호출했는데도
blocking을 하는 것이 가능한가요?
이미 recv buffer에는 데이터가 들어와 있는 상태입니다.

아래 답변하신 CharSya님의 말씀 중
recv()가 0을 리턴하는 것은 정상종료의 경우에 한해서입니다.
질문하신 분은 갑작스러운 사건에 의한 비정상 종료를 말씀 하는 듯 합니다.
(천재지변이라는 표현까지 있지 않았습니까? ^^)

정리합시다.
1. select()가 리턴을 하면
해당 소켓에 대해 바로 recv()를 호출해도 아무 문제없습니다.
peer host가 죽었는지 살았는지는 이 상황에서는 전혀 상관 없는 내용입니다.
일단 local host의 recv buffer에는 데이터가 들어와 있는 상태이기 때문입니다.

2. 비정상 종료에 대한 확인을 recv() 호출 직전은 아니더라도
그래도 해야겠다 하시면 2가지 방법이 가능합니다.

- TCP의 SO_KEEPALIVE 옵션을 이용할 수 있습니다.
장점은 어플리케이션 프로그래머는
이후의 처리에 대해서는 신경 안써도 된다입니다.
단 여기서, 이후의 처리라 함은 일정시간 동안(2시간)
데이터를 한번도 서로 주고 받지 않았을 경우 확인 패킷을 날리고 응답하고
하는 등의 일련의 작업을 의미합니다.
다만 어플리케이션 프로그래머는
리턴되는 에러값에 대해서만 정확히 처리해 주면 됩니다.
단점은 2시간 동안이나 놀고 있는 상태로 소켓을 열어 두어야 한다는 겁니다.
- 2시간이 길다면 어플리케이션 레이어에서
위와 동일한 내용의 작업을 처리해 주면 됩니다.
이 경우의 장,단점은
첫번째 경우의 장점이 이 경우의 단점이고,
첫번째 경우의 단점이 이 경우의 장점입니다.

한가지만 더 말씀 드리면
사실 2번과 같은 처리는 굳이 하지 않아도 알 수 있습니다.
peer host에 문제가 있어서 connection이 유지되지 못하고 있었다면
recv()나 send()를 하게 될 경우에도 알 수 있으니까요.
그럼에도 2번이 필요한 경우는 클라이언트가 데이터를 보내기 전에는
서버가 먼저 절대로 데이터를 보낼 일이 없는 경우가 되겠죠.
그렇다면 알 방법이 없으니까요.

익명 사용자의 이미지

여담이지만, 하이텔 게제동의 글을 읽어보면...

리눅스에서는 아니지만, 다른 OS의 경우 select 콜에서 분명히

read 이벤트가 발생했지만 recv에서 블럭되는 경우가 있다고 합니다.

(저 같은 경우는 linux 만 사용해봤다는 ^^ ), 그래서 select + 논블록킹

소켓의 조합을 이용하라고 하시더군요. 그럼 고운 하루...

ps. 옥정훈 님의 말씀대로 비정상적인 경우에는 알지를 못합니다. 그래서

보통 옥정훈님이 말씀하신 2-2 의 방법을 많이 사용합니다. 왜냐하면

SO_KEEPALIVE가 그 시간이 너무 오래걸리기 때문입니다. 일정 시간마다

소켓에 데이터를 보내고 그에 대한 응답이 오는지로 체크하면 됩니다.

옥정훈 wrote..
질문하신 분이 1가지 오해하고 있습니다.
select()와 함께 사용하는데
왜 recv()가 데이터가 없다고 blocking을 하죠?
select()가 readfd에 대해서 언제 리턴을 하는지를 다시 한번 생각해 보세요.
데이터가 왔기 때문에 리턴을 한 겁니다.
데이터가 왔기 때문에 그래서 recv()를 호출했는데도
blocking을 하는 것이 가능한가요?
이미 recv buffer에는 데이터가 들어와 있는 상태입니다.

아래 답변하신 CharSya님의 말씀 중
recv()가 0을 리턴하는 것은 정상종료의 경우에 한해서입니다.
질문하신 분은 갑작스러운 사건에 의한 비정상 종료를 말씀 하는 듯 합 니다.
(천재지변이라는 표현까지 있지 않았습니까? ^^)

정리합시다.
1. select()가 리턴을 하면
해당 소켓에 대해 바로 recv()를 호출해도 아무 문제없습니다.
peer host가 죽었는지 살았는지는 이 상황에서는 전혀 상관 없는 내 용입니다.
일단 local host의 recv buffer에는 데이터가 들어와 있는 상태이 기 때문입니다.

2. 비정상 종료에 대한 확인을 recv() 호출 직전은 아니더라도
그래도 해야겠다 하시면 2가지 방법이 가능합니다.

- TCP의 SO_KEEPALIVE 옵션을 이용할 수 있습니다.
장점은 어플리케이션 프로그래머는
이후의 처리에 대해서는 신경 안써도 된다입니다.
단 여기서, 이후의 처리라 함은 일정시간 동안(2시간)
데이터를 한번도 서로 주고 받지 않았을 경우 확인 패킷을 날리 고 응답하고
하는 등의 일련의 작업을 의미합니다.
다만 어플리케이션 프로그래머는
리턴되는 에러값에 대해서만 정확히 처리해 주면 됩니다.
단점은 2시간 동안이나 놀고 있는 상태로 소켓을 열어 두어야 한 다는 겁니다.
- 2시간이 길다면 어플리케이션 레이어에서
위와 동일한 내용의 작업을 처리해 주면 됩니다.
이 경우의 장,단점은
첫번째 경우의 장점이 이 경우의 단점이고,
첫번째 경우의 단점이 이 경우의 장점입니다.

한가지만 더 말씀 드리면
사실 2번과 같은 처리는 굳이 하지 않아도 알 수 있습니다.
peer host에 문제가 있어서 connection이 유지되지 못하고 있었다면
recv()나 send()를 하게 될 경우에도 알 수 있으니까요.
그럼에도 2번이 필요한 경우는 클라이언트가 데이터를 보내기 전에는
서버가 먼저 절대로 데이터를 보낼 일이 없는 경우가 되겠죠.
그렇다면 알 방법이 없으니까요.

익명 사용자의 이미지

linux이건 다른 os이건 간에, select에서 readable하다고 판단되어
도, 현재 read buffer에 있는 size보다 더 큰 size를 읽으려고 시도하
면 block하는 것으로(blocking socket의 경우) 알고 있습니다.

익명 사용자의 이미지

read buffer에 있는 size 보다 더 큰 size를 읽으려고 시도하면 block
이 된다는 것은 현재 read buffer 에 1000바이트가 들어있는데,
recv( sock, readBuffer, 4095, 0 );
이런식으로 사용하면 블럭이 된다는 뜻입니까?

실제로 사용해보면, 별 문제가 없던것 같은데, 좀 더 자세히

설명해주시거나, 자료가 있다면 올려주시길 바랍니다.

그럼 고운 하루되세요.

Anonymous wrote..
linux이건 다른 os이건 간에, select에서 readable하다고 판단되어
도, 현재 read buffer에 있는 size보다 더 큰 size를 읽으려고 시도하
면 block하는 것으로(blocking socket의 경우) 알고 있습니다.

익명 사용자의 이미지

잘못 알고 계십니다.
block 안 합니다.

익명 사용자의 이미지

커널 read buffer에 1000bytes의 자료가 있는 상황에서.

rtn = read(recv_fd, recv_buff, 4096);

이런식으로 read를 호출을 한다면 바로 리턴을 합니다.
rtn은 1000일테고 recv_buff에서는 1000바이트가 복사 되었겠지요.

read에서 size값은.. 읽어 드릴수 있는 양의 max를 주게 되는거죠
그래서 주로
rtn = read(recv_fd, recv_buff, sizeof(recv_buff));
요렇게 사용을 합니다.

read가 블럭킹 되는 경우는,
기본적으로 소켓이 블럭킹모드 이어야 겠고,
read buffer에 아무것도 없을 때겠죠..

ps. read에서 블럭일때, 상대편이 소켓을 닫을때
리턴되는데 이때 리턴값을 0을 줍니다.
이것을 보고 저쪽이 닫힌것을 알고 저도
close를 호출해 주는거죠.

익명 사용자의 이미지

말씀하신 방법은 특정 OS에서만 가능합니다. 단적인 예로, HP-UX에서
는 /proc/pid 라는 디렉토리가 존재하지 않는걸로 알고 있습니다. 제 경
험으론 그 방법은 SUN 기종에서만 사용하는것으로 알고 있습니다.

익명 사용자의 이미지

제가 그런 경우의 프로그램을 개발했었는데요.

일단 select()를 이용하구요, SIG_PIPE 시그널을 이용하시면 됩니다.

먼저 select()를 사용할때 socket fd로 select 합니다. 그런 상황에
서 접속이 끊어지면 select()에서 이벤트가 발생합니다. 그러면 socket
에 read를 시도합니다. read를 시도했을때 접속이 끊어진 상태이면 0을
리턴합니다. 이렇게 알아낼수 있구요.

실제로 read/write 중에 접속이 끊어지면 read/write 함수가 에러를
리턴합니다. 그렇기 때문에 별 문제가 않되죠.

그리고 read하다가 block되는 경우는 fd가 block모든인 상태에서 read
버퍼에 있는 데이터보다 더 큰 데이터를 읽으려할때 block됩니다.
예를 들어 버퍼에 100바이트가 있는데 1000바이트를 읽으려고 하면
1000 바이트가 다 받아질때까지 block됩니다. 단 이 경우에 fd가 non
blocking 모드이면 즉시 리턴하죠.

댓글 달기

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