한번에 write 하는데 수신쪽에서는 두개의 패킷으로 옵니다.

ajrroql7의 이미지

tcp 소켓에서 523 바이트를 한번에 write 하는데
패킷이 나갈때 스니퍼로 분석해 보면 500 바이트와 23 바이트
두개의 패킷으로 쪼개져 나가네요

소켓옵션을 조정해야 하는건지, send 버퍼를 늘려야 하는건지
옵션없이도 523 바이트면 큰것도 아닌데
이유가 먼지 궁금하네요

두개로 쪼개져 서버로 전달되는 서버에서는
첫 패킷만 받아 그게 전부줄 알고 처리되다보니
에러가 납니다. (서버는 고칠수는 없습니다)

아시는 분 도와 주세요

bejoy4him의 이미지

523바이트를 쓴다고 해서 항상 523바이트가 모두 한번에 전송되는 것은 아닙니다.
네트웍이나 여러가지 여건에 의해서 쪼개져서 보내지고 받도록 되어있습니다.

recv에서 한번만 받아서 다 받았다고 끝내지 마시고 정해진 길이만큼 다 받을때까지 반복해서 recv해야 합니다.
recv에서 한번만 읽고 다 받았다고 생각하면 거의 모든 경우에 문제가 됩니다. 서버가 문제가 아니라 클라이언트를 고쳐야죠...

예를 들면... 처음엔 헤더만 읽어서 메시지의 길이를 알아낸 후에...
그 길이만큼 다 받을때까지 루프를 돌면서 recv하면 된답니다.

ajrroql7의 이미지

서버를 고치면 해결이 되겠지만
고칠수는 없는 처지라.....

네트웍하고는 아무상관없이
랜 포트를 통해 실제로 2개로 나가니 나가니 문제지요

ssehoony의 이미지

ajrroql7 wrote:
네트웍하고는 아무상관없이
랜 포트를 통해 실제로 2개로 나가니 나가니 문제지요

네트워크의 의미를 인터넷으로 생각하셨나요?
이더넷장비(랜카드)의 mtu 값과 tcp 의 mss 의 값에 의해 송신측 커널이 데이터를 쪼갤 수 있습니다.
그러므로 송신할때 부터 쪼개져 있는거져.

udp 의 경우는 패킷 자체가 손실이 있을 수 있지만 송신사이즈 단위로 수신이 되는 특징을 갖고 있죠.
이것역시 mtu 값에 의해 작게 쪼개지기는 하지만 스트림이 아니기 때문에 송신사이즈가 결정되어있어서 수신측(수신측 커널)에서 이를 확인하고 해당 사이즈가 다 수신되면 application 에게 수신 이벤트를 던져주는거죠.

kihongss의 이미지

ajrroql7 wrote:
tcp 소켓에서 523 바이트를 한번에 write 하는데
패킷이 나갈때 스니퍼로 분석해 보면 500 바이트와 23 바이트
두개의 패킷으로 쪼개져 나가네요

소켓옵션을 조정해야 하는건지, send 버퍼를 늘려야 하는건지
옵션없이도 523 바이트면 큰것도 아닌데
이유가 먼지 궁금하네요

두개로 쪼개져 서버로 전달되는 서버에서는
첫 패킷만 받아 그게 전부줄 알고 처리되다보니
에러가 납니다. (서버는 고칠수는 없습니다)

아시는 분 도와 주세요

서버를 고칠수 없다니,
가능하면 서버와 같은 네트워크 환경 안에서
돌아갈 일종의 프락시 서버를 둬야할것 같군요.
클라이언트에서 나눠서 들어오는 패킷을 하나로 모아서
원래 서버한테 전송하고 서버가 프락시 서버한테
패킷을 보내면 프락시 서버가 다시 클라이언트에게...
같은 네트워크 환경이라도 프락시 서버가 원래 서버한테
전송하는 패킷이 나눠서 안 가리라는 보장은 없습니다. :cry:
왠만하면 서버 다시 짜시길 :D

익명 사용자의 이미지

패킷이 몇개로 오든 한번만 read해서 전체를 읽을 수 있다면 별 문제가 없지 않을까요? +_+?

하나의 write에서 두개로 패킷을 보내는건 네트워크에서 알아서 한걸테니까여 +_+;;

익명 사용자의 이미지

서버 고칠 수 없으면 다시 짜세요.
그것만이 올바른 해결입니다.
아니면, 운영체제(특히, TCP/IP스택)을 서버에 맞추어 다시짜던가. --;

*... 음 역시, 전자가 낫겠지요?

익명 사용자의 이미지

*전자도 조금 가혹하다면, 다른 하나의 방법은, 해서는 안되는 방법인듯 하지만, 이가 없으면, 잇몸이라도....

* 현재 문제는 recv()/read()가 523바이트를 읽어야 하는데,
523> 입력바이트수 라는 문제이지요.

해결(편법, 제약조건/가정을 가해야만 하는...)
가정)
1. 고정바이트다.
2. 열려진 파일 디스크립터들에서 소켓을 식별한다.
3. 프로그램이 recv()를 사용해서 구현되어 있으면 좋다.
...

방법:
1) recvN()과 같이 523바이트를 읽어야 리턴하는 함수를 구현한다.
2) recv()함수를 후킹해서 readN()에서 recv()를 호출하게 한다.

사용테크닉)
1) dlopen(), dlsym(), function pointer등으로 recv()를 사용자가 새로만든 함수로 가게 변경
2) 사용자가 새로만든 recv()는 항상 523바이트를 입력받아야 리턴하게 짠다.
3) LD_PRELOAD로 해당 라이브러리가 먼저 로드되게 한다.
4) 돌린다.

예상문제점)
* 만일 원래 서버프로그램이 recv()대신 read()를 사용했다면?
read()의 파라메터값을 검토하고, 만일 소켓에서 523바이트 읽는 read()라면 이로 대체한다. 따라서, 읽고자 하는 파일이 소켓인지를 구분할 수 있어야 한다.
* 만일, 소켓에서 읽을때, 값이 523이 아닌경우는? 글쎄다. 고민해봐야겠지.
* 읽는 문제를 해결할 수는 있으나, 사이드이펙트에 대해서도 한참고민해야 할것이다.
* 역시나, 다시 서버짜는게 좋아보인다. 서버 최초 코딩시, 이런점도(질문자의 문제점) 고려하지 않고 작성된 서버라면, 다시짜는게 건강에 좋을것 같다.

* 코드까지 짜달라고? 그러시면 아니되옵니다. 아님 다른 분들께서 짜주실지도.
* 그럼 방법이라도 보다 자세히? dlopen으로 KLDP검색해보고 조금 공부해보자. 그럼 길이 보인다.

* 완전한 해결책을 못드려서 죄송...

익명 사용자의 이미지

로그인하기가 귀찮아서 그냥 씁니다만...
두번째 글을 달았던 사람인데..
제가 답글을 달았을때는 메시지를 수신하는 쪽이 클라이언트인줄로 알았었습니다.
지금보니 코드를 수정할수 없는 서버가 메시지를 수신하는군요...

서버의 코드를 수정할수 없다면, 근본적인 해결책은 없다고 보는게 무방하겠네요. 소켓 옵션에 특정한 것을 넣어서 하면 좋겠지만 그것과 관련해서는 별로 들어본적이 없는것 같아서.... 서버를 그따위로 짜다니.. ㅡㅡ;;

일단 클라이언트가 송신할때 라우터같은 장비를 지날때가 부터 아닌 확실히 NIC 카드에서부터 2개로 쪼개서 보낸거라면, NIC카드의 Driver에서 그렇게 한것이 아닐까 하는 생각이 듭니다.

서버가 기존부터 쓰던 것이라면 클라이언트의 랜카드를 바꾸어 보거나 드라이버 버전을 바꾸어보는것도 해볼만한 일이 아닐까 합니다.

bejoy4him의 이미지

Anonymous wrote:
로그인하기가 귀찮아서 그냥 씁니다만...
두번째 글을 달았던 사람인데..
제가 답글을 달았을때는 메시지를 수신하는 쪽이 클라이언트인줄로 알았었습니다.
지금보니 코드를 수정할수 없는 서버가 메시지를 수신하는군요...

서버의 코드를 수정할수 없다면, 근본적인 해결책은 없다고 보는게 무방하겠네요. 소켓 옵션에 특정한 것을 넣어서 하면 좋겠지만 그것과 관련해서는 별로 들어본적이 없는것 같아서.... 서버를 그따위로 짜다니.. ㅡㅡ;;

일단 클라이언트가 송신할때 라우터같은 장비를 지날때가 부터 아닌 확실히 NIC 카드에서부터 2개로 쪼개서 보낸거라면, NIC카드의 Driver에서 그렇게 한것이 아닐까 하는 생각이 듭니다.

서버가 기존부터 쓰던 것이라면 클라이언트의 랜카드를 바꾸어 보거나 드라이버 버전을 바꾸어보는것도 해볼만한 일이 아닐까 합니다.


이글 제가 쓴 글인데.. 처음부터 로그인할걸 하는 생각이 드는군요...

만약 OS나 NIC카드, 드라이버만 바꾸어서 해결이 된다고 해도.. 그건 임시 방편일뿐, 실제 적용되면 적용이 되는 환경에 따라 "그때 그때 달라요"가 되는 참 난감한 상황이 발생할겁니다.

ssehoony의 이미지

쩝. 일단 mtu 값과 tcp 디폴트 mss 값을 각각 1500 과 1460 으로 수정해 보세요.
함 해보고 안되면, 그 때 다시 고민 ㅡ.ㅡ;

ajrroql7의 이미지

서버쪽은 상대가 은행이라서 맘대로 수정을 불가하고요

패킷이 두개로 쪼개져 나가는 문제는 어쨌던 저의 문제이다
보니 무조건 고쳐야 겠지요

현재 가능성있는것이 mtu, mru, mss 값인데
현재 mru, mtu 는 1492 이고 mss 는 1432 입니다.

우선 말씀하신데로 조금 높여 보고 결과를 말씀드겟습니다.

ajrroql7의 이미지

mtu, mss, mru 등을 조정해 봐도 결과는 마찬가지입니다.

참나

어떻게 해결해야될지 난감하네요

익명 사용자의 이미지

서버 앞단에 ip fragmentation을 reassemble해주는 일종의 라우터를 달아주는 엽기방법 외에능 없겠네요. 원래부터 프로그램을 잘못 만들었다고밖에....

익명 사용자의 이미지

* 서버가 은행에 있고, 서버내에 코딩이(새로운 프로그램 설치)가 불가능하다면, 은행내에 프록시서버를 하나 두는 방법이 좋겠습니다.
* 서버가 은행에 있고, 서버내에 코딩이(새로운 프로그램설치)가 가능하다면
- 서버시스템내에 프록시 서버프로그램을 작성해서 패킷을 버퍼링후 묶어서 보내주는 루틴으로 가능할지도
- 또는 서버의 운영체제 및 버전에 따라 차이가 있겠으나, LD_PRELOAD테크닉을 사용하여 라이브러리를 wrap하는 방법도 가능할지도

* 서버가 묘하게 만들어졌군요 --;

익명 사용자의 이미지

에고 전에는 올리신 글을 대충 읽어보고 답을 달아서 동문서답을 하게 되었네여 -_-;;

초기에 handshake 할 때 mss 값을 어떤 값으로 주고받나요? -_-?;;

서버쪽의 mss 값이 낮은건 아닌가 의심이 가네요.

익명 사용자의 이미지

아참 그리고 패킷이 보내질 때 하나의 패킷이 특정 설정에 의해서 쪼개진 것인지 확인해 보시는 것도.. -0-;; (이미 확인하셨으리라 생각되지만여.)

댓글 달기

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