블럭킹 소켓에서 select() 후 recv() 하는데..

dotri의 이미지

블럭킹 소켓으로 통신하는데요
select() 로 검사해서 읽기 가능할때 recv() 하거든요?
근데 select() 에서는 읽기 가능하다고 나오는데, 곧이어서 recv() 하면 블럭이 걸려요.
이런 상황이 언제 어떻게 있을 수 있나요? 그리고 해결방법은 어떤게 있을지..
윈도우 환경입니다.

lovemyin의 이미지

소스코드를 올려주실래요... 그 부분만이라도...

정상적으로 select가 동작하였다면 recv함수에서 블럭이 걸릴 이유가 없는데 이상하네요....
윈도우 환경에선 select 잘 안쓰는데... 어쨋든 너무 막연해서 소스코드라도 올리시는게 좋을것 같아요....

/***************************************************
* 가장 심플한 것이 가장 아름다운 것이다.
***************************************************/

frowt의 이미지

select 는 non-blocking 에서 주로 사용하고,
blocking 에서는 select 를 쓰는것은 글세요. 비추천입니다.
쓰려고 하면 못쓸것도 없지만요. 그건 그렇고,
blocking socket 에서는 recv 했을때 block 될수는 있을것 같고요
(windows blocking으로는 안해봐서 확실치 않음)
질문자의 의도를 유추 해보면, socket을 non-blocking으로 바꾸셔야 할것같네요.
아니면, blocking+select+alarm signal 식으로 하셔야 할듯
(참고로 이런식의 코딩을 어느 업체에서 해놓은걸 봤는데 짜증이 많이 나더군요)

익명 사용자의 이미지

시스템 버퍼에 있는 것보다 많은 양의 데이터를 recv하려고 해서 block되는 것 아닐까요? 1바이트만 recv하시는 건가요?

lopad의 이미지

Quote:
블럭킹 소켓으로 통신하는데요
select() 로 검사해서 읽기 가능할때 recv() 하거든요?
근데 select() 에서는 읽기 가능하다고 나오는데, 곧이어서 recv() 하면 블럭이 걸려요.

저도 님과 같은 현상을 경험했습니다. 저의 환경은 compaq proliant 8500 머신에 솔라리스 x86 8이고 gcc 2.95.2 입니다.

증권사 서버 프로그램인데 이런 경우가 발생해서 곤역을 치룬적이 있습니다.. 여기 포스팅도 했지만 해결책을 못 찾았습니다.
block를 격리하는 방법으로 접근했습니다. 즉 client별로 dedicated thread를 붙여서 처리했습니다.

그리고 아울러 tcp_keep_alive 시간을 기본 2시간에서 5분정도로 조정했습니다.

아직도 원인이 궁금합니다. OS 버그인지 프로그램 버그인지.... 아니면 외부의 요인인지..

익명 사용자의 이미지

* water mark를 키워드로 검색해보시기 바랍니다.

* 아마도 water mark 문제로 보입니다.
* 다음을 테스트 해보세요.
서버에서 accept()한 후 새로이 생성된 클라이언트와 연결된 소켓에 대해, 아래 코드를 돌려보세요.

요약: 아래 코드는 기본(디폴트) 수신최소워터마크를 출력하고,
무조건 수신최소워터마크를 1로 변경하여 1바이트만 들어와도 이벤트를 발생시키게한다.

void setRcvLowWaterMark(int sockfd)
{
   int oldWatermark;
   int myWatermark;
   int ret, optlen;

   optlen = sizeof(int);
   ret = getsockopt( sockfd, SOL_SOCKET, SO_RCVLOWAT, (char *)&oldWatermark, &optlen);  
   if ( ret < 0 ) {
       printf("에러...");
       return;
   }
   printf("현재(기본) 최소 수신 워터마크 = %d\n", oldWatermark);

   myWatermark=1;
   ret = setsockopt( sockfd, SOL_SOCKET, SO_RCVLOWAT, (char *)&myWatermark, sizeof(int));  
   if ( ret < 0 ) {
       printf("에러...");
       return;
   }
   printf("앞으로 최소 수신 워터마크 = %d\n", myWatermark);
}

참고 :
1. bbs.kldp.org에서 water and mark를 키워드로 검색해본다.
2. http://archives.neohapsis.com/archives/postfix/2001-11/1503.html

익명 사용자의 이미지

Anonymous wrote:
* water mark를 키워드로 검색해보시기 바랍니다.

* 아마도 water mark 문제로 보입니다.
* 다음을 테스트 해보세요.
서버에서 accept()한 후 새로이 생성된 클라이언트와 연결된 소켓에 대해, 아래 코드를 돌려보세요.

요약: 아래 코드는 기본(디폴트) 수신최소워터마크를 출력하고,
무조건 수신최소워터마크를 1로 변경하여 1바이트만 들어와도 이벤트를 발생시키게한다.

void setRcvLowWaterMark(int sockfd)
{
   int oldWatermark;
   int myWatermark;
   int ret, optlen;

   optlen = sizeof(int);
   ret = getsockopt( sockfd, SOL_SOCKET, SO_RCVLOWAT, (char *)&oldWatermark, &optlen);  
   if ( ret < 0 ) {
       printf("에러...");
       return;
   }
   printf("현재(기본) 최소 수신 워터마크 = %d\n", oldWatermark);

   myWatermark=1;
   ret = setsockopt( sockfd, SOL_SOCKET, SO_RCVLOWAT, (char *)&myWatermark, sizeof(int));  
   if ( ret < 0 ) {
       printf("에러...");
       return;
   }
   printf("앞으로 최소 수신 워터마크 = %d\n", myWatermark);
}

참고 :
1. bbs.kldp.org에서 water and mark를 키워드로 검색해본다.
2. http://archives.neohapsis.com/archives/postfix/2001-11/1503.html

아니오. 그렇지 않습니다.
select() 리턴 시점이 바로 그 water mark 를 넘어서 버퍼에 데이터가 들어왔을때입니다.

jinyeong의 이미지

select 등의 readness notification을 사용하실 때에는 nonblock io를 하시는 것이 좋습니다.

http://www.kegel.com/c10k.html

Quote:

Note: it's particularly important to remember that readiness notification from the kernel is only a hint; the file descriptor might not be ready anymore when you try to read from it. That's why it's important to use nonblocking mode when using readiness notification.
- The C10K problem

I thought what I'd do was,
I'd pretend I was one of those deaf-mutes.. or should I?

pynoos의 이미지

select 한 뒤 해당 소켓의 recv에서 수신할 것이 없어서 block되는 현상이 다음과 같은 예 외에 더 있을까요?

1. 두 개의 프로세스에서 레퍼런싱하고 있는 socket을 select하고 두 프로세스가 동시에 깨어난 뒤(실제 그렇죠) 한 쪽에서 읽기 버퍼를 모두 읽어서 다른 한 쪽은 블럭이 된다.

2. select한 소켓에 대하여 FD_ISSET으로 확인하지 않고, 실제 데이터가 도착한 소켓이 아닌 다른 소켓을 읽기 시도하여 블럭이 된다.

3. 특수한 커널 모듈이 들어가서 select와 recv 중간에 그 모듈이 제어권을 얻고, 버퍼를 비워버린다.

이상의 경우가 아닌 다른 경우인지 확인 부탁드리구요.
또하나 확인할 것은, 저 현상이 정말 자주 일어난다면 nonblock I/O로 select 한 다음 EAGAIN 오류가 발생하면 바로 다시 select 한번 해보세요. 그 때에도 select의 리턴값이 1 인지 확인가능하시면 시도해보세요.

select는 수신 버퍼의 level(water mark)이상인지를 확인하는 방식으로 일어나기 때문에 뭔가 다른 곳에 오류가 있어보이는군요.

nonblock I/O를 추천하시는데, 사실 recv에서 nonblock I/O는 잘 고려했는데, 같은 소켓을 이용하여 send 할 때 에러처리하지 않아서 데이터가 유실되는 상황도 충분히 고려해야합니다. 이 경우 전송지연때문에 생길 수 있는 송신 버퍼꽉참도 고려해야하며 따라서 송신 시도 스케쥴 등 상당히 고려할 것이 많아집니다.

댓글 달기

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