[질문]VC++에서 CAsyncSocket에서 Send Buffer 보다 큰 사이즈를

paraline의 이미지

궁금한게 있어서 devpia에 질문을 올렸었는데, 만족할만한 답변이 없어서 여기에도 올려봅니다.
혹시 질문 자체가 이해가 안되시면 답글 주시면 다시 올리겠습니다.
아래의 CAsyncSocket은 논블럭으로 동작합니다.

Quote:
Socket에서 Send 함수가 리턴하는 값은 실제로 전송된 값이 아니라, Socket의 Send Buffer에 write한 값이라고 알고있습니다.
그렇다면, 실제 Send Buffer보다 큰 값을 Send하려고 한다면, 리턴값은 Socket Send Buffer 사이즈 만큼이고 나머지는 나중에 Send Buffer가 비었을때, 다시 전송이 되어야 할것 같은데, 테스트 결과는 그렇지 않더군요. 테스트를 위해서, Remote Socket에서는 Receive를 하지 않았습니다.
GetSockOpt로 Send Buffer Size를 보니까, 8192로 나왔습니다.

그런데,
int nSend = Send(buff, 8192 + 1000);
이렇게 해도 nSend 가 9192가 나오는군요.

왜 그런지 언뜻 이해가 안갑니다.
Send 내부에서는 단순히 socket api 함수인 send()만 호출하던데, Send Buffer Size보다 큰 값이 Send 되었다고 리턴되는 이유를 모르겠네요.

프로그래밍 자체의 문제는 없습니다만, 갑자기 궁금해져서 질문 올립니다. ^^

익명 사용자의 이미지

설명을 위해 몇가지를 정의합니다.

1) 통신 개체
A : 송신 프로그램
B : 송신측 운영체제
C : 수신측 운영체제
D : 수신 프로그램

2) 통신유형
2-1) A->B : 송신프로그램에서 송신측 운영체제로 전송(MFC send())
2-2) B->C : 송신 프로그램과 관계없이 양단간의 운영체제끼리의 통신
2-3) C->D : 원격지 운영체제와 원격지 수신프로그램간의 통신

* 질문자의 오류
if ( D가 수신안하면 ) {
2-2 즉, B->C도 동작안할 것으로 오해함;
}

* 참고
B->C는 C의 수신버퍼가 찰때까지 동작합니다.

* 원하는 테스트를 하려면?
1) 원격지 버퍼를 가득 채울 만큼을 송신 : 이때 원격지 수신프로그램은 당근으로 recv()하면 안됨.단지 얼마나 수신되었나 검사하는정도라면 오케이!
2) 그후 송신자는 로컬송신버퍼의 크기만큼을 전송해본다. 만일 원격지
운영체제의 수신버퍼가 full이라면 질문에서 예측했던 값이 리턴될 것임.
3) 로컬 커널 송신버퍼 + 원격지 커널 수신버퍼 <=== 잘 ~ 생각해본다.

익명 사용자의 이미지

부연해서 설명하자면,
송신자 : 철이
송신운영체제 : 철이네 동네 우체국
수신운영체제 : 영이네 동네 우체국
수신자 : 영이

영이가 안받으려고 해도, 철이가 일단 동네 우체국에
편지 넣으면, 영이네 동네까지는, 철이가 뭐라고 하건
영이가 뭐라고 하건간에 간다! 도로가 끊기거나, 천재지변이
없다면 말이다.

paraline의 이미지

먼저 답변에 감사드립니다.

Quote:
* 질문자의 오류
if ( D가 수신안하면 ) {
2-2 즉, B->C도 동작안할 것으로 오해함;
}

제가 오해할만하게 질문을 드렸군요. ^^
실제로 제가 테스트 했던건 1000000정도의 사이즈였습니다.
당연히 수신측에서는 Receive()를 안해줬고요.
그런데, GetSockOpt로 검사해보니, 송신측 send buffer와 수신측 recv buffer의 크기가 8KB였습니다.
그렇다면, 분명히 송신측 send buffer와 수신측 recv buffer가 꽉 차게되서 몇번에 나누어서 send가 되던가, 아니면, wouldblock이 리턴되어야 할것 같은데, Send() 한번에 1000000이 바로 리턴되는군요. ^^

좌절금지!!!
피할수 없다면 즐겨라.

bugiii의 이미지

사용자에게 보이는 소켓버퍼말고도 구현에 따라 내부적으로 버퍼가 있을 수 있습니다. 윈도우의 경우 (문서가 기억이...) 분명히 내부적으로 소켓 버퍼를 따로 가지고 있습니다. 그 문서에는 윈도우 같은 경우 보내기 소켓 버퍼를 0으로 하고 비동기 Overlapped I/O 를 잘 사용하면 Zero Copy 전송을 구현할 수 있고 고성능의 보내기를 수행할 수 있다고 합니다. 하지만, 읽기 동작은 이렇게 해서는 소용없고 오히려 내부 버퍼를 더 키우는 결과를 가져온다고 읽었던 기억이 있습니다. 물론 FreeBSD 도 메모리를 잘 맞추면 이를 이용해서 이런 상황을 만들 수 있습니다.

하여간, 소켓 버퍼가 얼마인가를 신경쓰시는 것보다는 덜 보낸 경우 다시 보내는 부분만 (잘하고 계신다니) 잘 해주시면 될 것 같습니다.

paraline의 이미지

Quote:
윈도우의 경우 (문서가 기억이...) 분명히 내부적으로 소켓 버퍼를 따로 가지고 있습니다. 그 문서에는 윈도우 같은 경우 보내기 소켓 버퍼를 0으로 하고 비동기 Overlapped I/O 를 잘 사용하면 Zero Copy 전송을 구현할 수 있고 고성능의 보내기를 수행할 수 있다고 합니다. 하지만, 읽기 동작은 이렇게 해서는 소용없고 오히려 내부 버퍼를 더 키우는 결과를 가져온다고 읽었던 기억이 있습니다.

아, 그렇군요.
이렇게 생각하니까 말이 되네요.
답변 정말 감사합니다.
막힌 속이 뻥 뚫렸습니다. ^^

좌절금지!!!
피할수 없다면 즐겨라.

댓글 달기

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