select 를 통해서 blocking 소켓을 구현하면 문제가 되나요?

jos77의 이미지

어차피 select 를 socket event wait 함수처럼 사용할 예정이었습니다.

멀티쓰레드로 여러 프로세스 띄워놓으면 복잡할 것 같기도 하고, 애당초 부하가 많이 걸리는 socket 이 아닙니다.

문제는 가변 패킷 사이즈를 주고 받을 때 non-blocking 으로 설정할 경우,
패킷을 일부 받고 마저 일부 받는 프로세스를 상정할 경우 제어를 하기가 어렵습니다.

항상 4byte 패킷을 먼저 받아 size 를 확인한 후 , 해당 size 만큼 받아야 되는데 그러려면 read() 를 두번 호출합니다. 그러면 필연적으로 두번째 read 는 blocking 이 될 수밖에 없습니다.

select 를 blocking 소켓으로 구현하게 되면 어떤 문제가 있을 수 있나요? 한 소켓의 블럭킹 때문에 다른 소켓이 완전히 막히나요? 그럼 socket buffer 가 꽉 차게 되는 현상이 있을 수 있나요?

차라리 멀티 쓰레드로 각각 소켓을 따로 갖고 있는 프로세스로 구현하는게 나을까요? 조언 부탁드립니다.

ssehoony의 이미지

blocking 소켓이더라 하더라도, select 를 통해 read event가 발생한 것을 확인한 후에 read 함수를 호출하게 되면
socket read buffer에 기록된 데이터 만큼은 blocking 없이 read가 가능합니다.

select 를 통해 read event 를 모티터링 후, read를 통해 데이터를 최대한 읽습니다.
읽은 데이터 중 앞 4바이트를 통해 사이즈를 확인하고, 이 정보를 이용해 다 읽지 못했다는 것이 확인되면
다시 select 를 통해 read event를 기다립니다. read event가 발생하면, 이전에 읽은 데이터에 새로 읽은 것을 append하고
다시 원하는 size만큼 읽었는지를 확인하는 것을 무한 loop을 통해 반복하면 됩니다.
물론, select을 통해 다수의 fd를 관리 할 것이므로 read함수를 통해 읽은 데이터를 저장할 buffer를 fd 개수만큼 미리 준비 놓고 fd값을 확인해서 자료를 관리하면 됩니다.

매우 많은 fd를 처리하는 것이 아니라면, multi-thread에 bloking 소켓을 사용하는 것이 구현상 편합니다.
구현이 편하기 때문에, 코드도 단순해서 다른 사람이 이해하기도 좋습니다.
그래서 multi-thread로 구현이 가능하다면 이를 추천하지만,
만약 fd가 매우 많다면 multi-thread가 성능 저하의 원인이 될 수 있습니다.
다수의 cpu core를 활용하면서 다수의 fd를 처리하고 싶다면, boss-worker 모델의 thread pool 구조로 구현하시는 것을 추천합니다.

jos77의 이미지

fd 수는 5~6개 정도로 많지 않은데, 안그래도 thread 의 수가 많아서 굳이 server 소켓을 위해 thread 의 수를 늘리고 싶지가 않았거든요 ㅠ.ㅠ

문제는 다 읽지 못했다는 걸 확인하고 다시 read event 를 기다린다는 것 자체가 non-blocking 소켓 아닌가요?
blocking 소켓 자체가 read 하고 있는 동안 꽉 잡고 있다는 것을 뜻하는 건 줄 알았는데... --a;;

non-blocking 소켓으로 할 경우 에러처리라고 해야 하나... E_WOULDBLOCK 같은 에러가 발생할 경우에 대해 현재 받던 데이터 였는지 아니면 새로 받아야 되는지 헷갈리게 되더군요. 그밖에도 좀 buffer 들 관리하기 어려운 측면도 있고...

multi-thread 를 하고 싶긴 한데 팀원들의 반대가 만만치 않을 것 같아 고민중입니다 ^^;;

-----
안녕하세요 소프트웨어 공학센터 장원석 책임입니다.
http://www.software.kr

klutzy의 이미지

숙제 정도의 프로그램이라면 모르겠지만 일반적인 상황에서 recv(len=4)를 한 다음 recv(len=다음에_읽을_사이즈)를 한다고 해서 버퍼에 그 읽으려는 사이즈만큼의 데이터가 다 있을 거라는 보장은 없습니다.

심지어는 recv(len=4)를 했는데 1바이트만 나올 수도 있습니다. 소켓에서 데이터를 읽을 때는 몇바이트가 읽혔는지를 항상 확인해 주어야 해요.

select에 있는 소켓마다 버퍼 공간을 하나씩 두고, 버퍼에 데이터를 계속 쌓아두면서 데이터가 완전히 들어왔는지를 체크하세요. 예를 들어 사이즈 판독에 필요한 4바이트가 들어왔는지 보고, 들어왔으면 이후 사이즈만큼 데이터가 올때까지 계속 버퍼에 쌓아 두세요.

jos77의 이미지

read 를 통해 한번에 다 못 읽은 경우에 return 하는 소켓을 가리켜 non-blocking 소켓으로 부르는 거 아니었나요?

원 질문은 select 로 blocking 소켓을 구현했을 때 어떤 문제가 생길 수 있는지 / 해결 방법이 어떤게 있을지 였구요 ;; non-blocking 소켓으로 구현할 경우에는 ㅠ.ㅠ size 받을 때랑 한바퀴 돌아서 size 가 아닌 data 받을 때 구별하는 처리가 복잡해져서 가능한 안 하고 멀티 쓰레드로 할 예정이었거든요

-----
안녕하세요 소프트웨어 공학센터 장원석 책임입니다.
http://www.software.kr

klutzy의 이미지

non-blocking은 읽을 게 없을 때에도 리턴하는 경우입니다. 블로킹 소켓도 1바이트라도 읽을 게 있다면 리턴하고요. size보다 적은 숫자를 리턴하는 상황이 꽤 흔해요. MSG_WAITALL 플래그를 주면 size만큼 읽지만, 어차피 이것도 소켓 에러가 나면 size보다 적게 읽으니 예외 처리는 다 해줘야 합니다.

이런 이야기를 굳이 꺼냈던 이유는, select로 구현할 경우 이런 문제까지 모두 고려해야 하기 때문에, 그냥 버퍼를 두고 매번 데이터가 올때마다 데이터가 전부 있는지 일일히 확인해야 한다는 의미였습니다. 4바이트 헤더를 읽었으니 그 다음에는 블로킹으로 적당히 읽어도 된다고 가정하는 건 위험합니다. 그래서 원질문보다 더 일반적인 대처방법을 설명드렸던 거고요.

원 질문에 답하자면, 블로킹 소켓은 데이터가 올때까지 무한정 기다리고, 데이터가 언제 올지는 아무도 장담할 수가 없습니다. select는 블로킹을 피하기 위해 쓰는 것이고, 그래서 select 내에 블로킹을 쓰는 것은 위험합니다. 예를 들어 클라이언트에 문제가 생겨서 헤더만 보내놓고 다운된다면 서버도 같이 잠들어버립니다.

다음 글도 같이 참고하세요.

* http://rein.upnl.org/wordpress/archives/680
* http://www.kegel.com/c10k.html

댓글 달기

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