socket 질문입니다.

익명 사용자의 이미지

서버쪽에는 받는 것만있습니다.즉
while(1){
recv();
printf(받은메세지);
}

이런식이구요
클라이언트는 보내는것만있는데요

for(10번반복){
send(msg);
}

이렇게 하면 서버쪽에서 받은 메세지에 대한 출력을
msg
msg
msg
msg
...
이런식으로 나와야 하는데
msgmsgmsgmsgmsgmsgmsg... 이런식으로 한번에 나와버립니다.
아마 클라이언트에서 send 할때 socket send buffer 때문인거 같은데요
이거
msg
msg
msg
msg
...
이런식으로 서버가 각각 받을려면 어떻게 처리 해줘야하나요?

익명 사용자의 이미지

water wrote..
서버쪽에는 받는 것만있습니다.즉
while(1){
recv();
printf(받은메세지);
}

이런식이구요
클라이언트는 보내는것만있는데요

for(10번반복){
send(msg);
}

msg = "내용\n";

이 되면 되겠죠.

이렇게 하면 서버쪽에서 받은 메세지에 대한 출력을
msg
msg
msg
msg
...
이런식으로 나와야 하는데
msgmsgmsgmsgmsgmsgmsg... 이런식으로 한번에 나와버립니다.
아마 클라이언트에서 send 할때 socket send buffer 때문인거 같은데요
이거
msg
msg
msg
msg
...
이런식으로 서버가 각각 받을려면 어떻게 처리 해줘야하나요?

익명 사용자의 이미지

msg\n
이렇게 하면 출력은
msg
msg
msg
...
이렇게 돼나 결국은 msg\n 을 연속으로 받은것 뿐이 않됩니다
즉 문제 해결이 않돼는거죠 ^^;;

익명 사용자의 이미지

그게 당연한겁니다. TCP/IP는 send 와 recv 가 11 대응이 되지 않습니
다.

즉, 여러번 보내도 한번에 받을수 있고, 그 역도 성립합니다. 그럼

고운 하루되시길...

익명 사용자의 이미지

보낼 때 사이즈 정보를 넣어서,
각 패킷을 두번씩 읽으면 해결될듯..

while {
첫번째 읽을때는 사이즈,
두번째는 사이즈 만큼 읽기
}

구현의 예)
http//kldp.org/script/bbs/read.php?table=qa2&no=584

익명 사용자의 이미지

링크가 된 내용을 읽어 보았습니다.
일정 크기를 다 읽을 때까지 recv()를 반복하는 wrapping 함수군요.

그런데 그 방법은 문제가 있습니다.
악의를 가진 사람이 1바이트짜리 데이터를 보내고
무한루프를 돌면서 sleep()을 해 버린다면
recv()를 호출한 쪽은 마냥 기다릴 수 밖에 없겠네요.

보완이 필요합니다.

익명 사용자의 이미지

제가 올린것은 블럭킹 모드일때의 함수이고,,
넌블럭킹 모드는 따로 함수가 있습니다.
그것은 궁금증을 가진 분들을 위해서 남겨둔 부분이죠
다 알려주면 개발이나, 이해의 즐거움을 뺏는 거니까요..

또 예전에 올린 소스에 약간 버그도 있어서
저기에 한가지 고친것두 있구요 ^^

버그 찾아보세요 ^^

익명 사용자의 이미지

제가 보완이 필요하다고 말한 것의 내용이
바로 non-blocking으로 해야 한다는 것이죠.

그리고 이 경우에는
blocking 모드와 non-blocking 모드
두가지의 버전이 있다고 말할 수 없는 내용입니다.
왜냐하면 blocking 모드는 제가 앞서 말한 이유로
사용할 수 없기 때문입니다.
사용할 수 없는 방법을 하나의 버전이라 할 수는 없는 거 아니겠습니까?

익명 사용자의 이미지


흠... 코드상에
조그만 문제의 소지가 있을 수 있는 부분이 있는 것 같아여.. ^^

1. 일단 커멘트에서 말씀하신대로 바이트 오더를 적절히 처리해 주심 좋
을 것 같구여, 이 경우는 가능성이 훨씬 더 적겠지만, size를 표시하는
정수의 크기가 달라질 수도 있으니 16, 32, 또는 64 비트 등 uint32_t 같
이 명시적으로 그 길이를 지정해서 쓰는 게 좋을 것 같습니다.

2. ReadSize() 함수를 보면 rtn=recv(fd, p, sz, 0); 을 수행한 후 if
(rtn <= 0)인 경우에는 errno * -1 을 리턴하고 있는데요,
문제는 이전에 발생한 오류에 인한 errno는 그 후에 정상적으로 수행된
연산에 의해서 clear되지 않는다는 것입니다. 즉, 상대방이 소켓을 닫아
서 recv()에서 0을 리턴했을 때, 이전 연산(fopen()을 했건 다른 파일을
read를 했건...)이 실패했었다면 결과적으로 부정확한 errno가 리턴되
고, 이는 호출한 곳에 부정확한 정보를 줄 수 있는 가능성이 있다는 것입
니다. 따라서 함수 앞쪽에서 errno 를 0으로 명시적으로 clear 시키거나
ReadSize는 recv()의 리턴값을 그대로 리턴하고 상위에서 이를 해석하는
것이 조금 더 정확한 처리가 될 것입니다. 물론 이런 현상이 일어날 가능
성은 매우 낮습니다.

3. WriteSize()에는 아마 배성남님이 버그라고 말씀하신 것이 있는 듯 합
니다. ^^
rtn = send(fd, p, sz, 0); 수행후에 if (rtn < 0) 을 먼저 수행해서 rtn
이 실제로 보낸 길이를 나타내는지 오류 상황을 나타내는지를 검사했어
야 하는데 if (rtn < sz) 를 먼저 수행해서 rtn을 무조건 보낸길이로 간
주해서 문제가 발생할 수 있죠. 만일 오류가 발생하면 -1이 리턴될테고,
이렇게 되면 sz -= rtn; 이 수행될테니까 이 경우에는 sz이 계속 증가해
서 overflow가 일어나 음수로 넘어가는 순간(이 경우 보통 표현할 수 있
는 가장 큰 음수로 넘어가겠죠) -1 보다 작게 되어 세번쩨 if 문으로 들
어가게 되어 리턴되겠죠. 함수외부에서 볼때는 send()에서 오류가 났고,
WriteSize()에서도 오류가 리턴되어오니까 그냥 넘어갈 수도 있겠지만,
가끔 순간적인 폭주 현상을 겪을 가능성이 있을 것입니다. 자주 발생하
는 오류가 아니라서 발견되지 않고 있다가 서비스장비에서 이런 일이 일
어난다면 더 큰 문제이겠고요.
모듈에서 사용하는 것으로 보이기는 하지만, 사악하거나 부주의한 상대방
을 만난다면 buffer overflow를 낼 수 있는 부분이겠고요.
WriteStream() 도 temp 영역에 크기를 검사하지 않고 memcpy()를 하기 때
문에 유사한 문제가 있지만 ReadStream() 보다는 훨씬 더 많은 제어를 가
지고
4. ReadStream()은 buff에 얼마나 많은 데이터가 올지 모른다는 문제가
있습니다. 테스트 프로그램이나 내부적으로 전송되는 최대길이가 얼마다
라는 assertion이 있는 경우가 아닌 실제 외부로부터 입력을 받아야 하
는 경우에는 문제가 발생할 수 있습니다. (흠.. 다 아시는 말들을 할려
니.. -_-;;) 아마 미리 보낼 사이즈 먼저 주고, 그 후에 데이터주고 하
는 루틴, MAX_BUFF 등의 상수를 보아서는 호출방법이나 지켜야 할 사항
이 상호 합의된, 협동적인 있으니 가능성은 훨씬 떨어지리라 생각됩니
다. 또 MAX_BUFF가 있으니 호출하는 함수에서 크기를 검사할 때도
WriteStream()을 호출할 때 MAX_BUFF만큼 되도록 assert 할 가능성이 있
는데, MAX_BUFF가 아닌 MAX_BUFF - sizeof(int)의 데이터만이 전달되도
록 주의할 필요도 있겠구요.

음...
WriteStream()나 다른 함수들의 코멘트상의 리턴값과 실제 코드상에서 리
턴하는 것이 틀리거나 정확치 않다는 것도 버그후보가 되나요?

WriteStream() 쪽은 send()대신 sendmsg()를 쓰면 임시버퍼를 안 두어도
되고, 이로 인해 발생할 수 있는 버퍼 오버플로우를 방지할 수도 있지 않
을까 함 생각이 드네여.

익명 사용자의 이미지

블럭킹 모드일때는 님이 말씀하는 현상이 생기는것은
분명한 일입니다.

그러나,
제가 만든 시스템에서는 내부 서버들이 통신을 하는데
굳이 넌블럭킹으로 인한 cpu cycle을 낭비할 필요가 없다는
것이죠.. (사용자를 신뢰한다는 의미입니다.)

아, 그리고 버전이 넌블럭킹모드와 블럭킹모드 두가지 있다고했는데
언밀히 말하면 블럭킹 모드는에 TimeOut기능이 추가된

int ReadSizeT(fd, buff, size, sec)
int ReadStreamT(fd, buff, sec)
이런 함수가 있고

또 ...님이 말씀하신 바이트오더에 상관없는
int ReadStream2T(fd, buff, sec)가 존재하지요.

/****
unsigned char size[2];
rtn = ReadSizeT(fd, (char *)size, 2, sec);
if(rtn <= 0) return rtn;
sz = size[0] * 255 + size[1];
****/

또, ...님께서 문제의 소지가 있는 부분을
지적해 주셨는데, 맞는 말씀입니다.
3번같은 경우엔 실제로 저런 버그가 생겨서
찾는다고 삽질(?)좀 했지요...
좀더 안전한 코드가 될려면
사이즈 처리에 대한 부분도 들어가야 겠구요.

두분의 글에 감사드립니다.

익명 사용자의 이미지

또 ...님이 말씀하신 바이트오더에 상관없는
int ReadStream2T(fd, buff, sec)가 존재하지요.

/****
unsigned char size[2];
rtn = ReadSizeT(fd, (char *)size, 2, sec);
if(rtn <= 0) return rtn;
sz = size[0] * 255 + size[1];
****/

음.. 이 경우는 아마 코드를 가져오신게 아니라 손으로 코드를 옮기신 것
으로 생각되는데여, 255가 아니라 일반적으로 256을 곱하는 것이 맞을 듯
싶고요, 혹시 실제 코드상에서도 256이 아니라 255를 쓰신 경우 문제가 발
생하지 않았다면 보내는 크기가 256 미만의 것이 거나 뒷쪽 데이터가 유실
되어도 큰 문제가 발생하지 않는 경우였지 않았을까 추측이 되네여.

보통은 256 나누고 곱하고 하는 것보다 htonl/s(), ntohl/s() 등의 제공되
는 함수를 사용하는것이 좀더 편한 방법이겠죠.

익명 사용자의 이미지

쓰는쪽 역시 이런식 이라서 문제는 안됩니다.

int WriteStream2T(fd, buff, sz, sec)
int fd, sz;
char *buff;
int sec;
{
int rtn;
unsigned char fs, ls, temp[MAX_BUFF];
fs = (unsigned char)(sz / 255);
ls = (unsigned char)(sz - fs * 255);
temp[0] = fs;temp[1] = ls;
...

익명 사용자의 이미지

;블럭킹 모드일때는 님이 말씀하는 현상이 생기는것은
;분명한 일입니다.

;그러나,
;제가 만든 시스템에서는 내부 서버들이 통신을 하는데
;굳이 넌블럭킹으로 인한 cpu cycle을 낭비할 필요가 없다는
;것이죠.. (사용자를 신뢰한다는 의미입니다.)

안녕하세요 배성남님 ^^
위에 제가 글을 쓴 건 님의 코드를 보고
하나하나 따질려는게 아니었습니다.
더군다나 남의 코드 하나하나 짚어가면서
이건 어쩌니 저건 어쩌니 하고 트집 잡아 가면서 기쁨을 느끼는,
그런 정도의 초보도 아니구요 ^^

다만 보안상의 문제가 있을 수 있다는
큰 줄거리를 말하고 싶었던 것 뿐입니다.

그런데 배성남님이 쓰신 위의 글을 읽고
cpu cycle을 낭비하지 않는 방법도 있다는
말씀을 드리고 싶습니다.

익명 사용자의 이미지


네.. ^^

전철 타고 오다가 보낼때도 그렇게 하면 될 것 같은 생각이 들어
글 지우러 왔더니만 벌써 꼬리가 달렸네요.. ^^

익명 사용자의 이미지


안녕하세요 배성남님 ^^
위에 제가 글을 쓴 건 님의 코드를 보고
하나하나 따질려는게 아니었습니다.
더군다나 남의 코드 하나하나 짚어가면서
이건 어쩌니 저건 어쩌니 하고 트집 잡아 가면서 기쁨을 느끼는,
그런 정도의 초보도 아니구요 ^^

다만 보안상의 문제가 있을 수 있다는
큰 줄거리를 말하고 싶었던 것 뿐입니다.

이건 어쩌니 저건 어쩌니 하고 트집 잡는 것하고,
Weinberg가 말하는 egoless programming이나
아니면 요즘 많이 말하는 peer review 등이 뭐 그게 그거 아니겠어여?
제 생각에는 종이 한장 차이 같아여.. 종이 한장이 때로는 큰 공력의 차
이이고, 결과에서도 큰 차이를 일으키지만여.. ^^
트집잡는건 초보도 하지만 egoless programming이나 peer review는 상당
한 경험이 있는 프로그래머들도 하져.. ^^

배성남님 코드 보면서 혹시 Nagle algorithm과 delayed ACK에 의해서 성
능 떨어지는 문제가 있을까 생각해 봤는데 (이 내용 다시 새겨보느라고
좀 시간이 걸렸습니다. 제가 책을 다른 곳에 두고 오는 바람에..)
WriteStream()에서 버퍼에 모아 한번에 쓰기 때문에 크게 문제가 안될 것
으로 생각했습니다.

평소 배성남님 글이나 홈피 가 보면서 훌륭하구나 생각하고 있었는데, 배
성남님 코드에서 '버그'가 있다고 하고 그걸 찾아보라니 얼마나 흥분되겠
습니까? ^^ 신난 김에 주저리주저리 몇마디 더 붙인거져.. ^^ 뭐 그런것
도 이 분야의 재미 중 하나 아니겠습니까? ^^


그런데 배성남님이 쓰신 위의 글을 읽고
cpu cycle을 낭비하지 않는 방법도 있다는
말씀을 드리고 싶습니다.

무슨 방법일까여?
poll? select? aio? alarm?
흠...

익명 사용자의 이미지

답글에 답글에.. 주루룩..
글이 무거워져 버렸네요.

저 또한 서로를 존중하면서 토론하는것을 좋아라 합니다.
두분 때문에 제가 작성한 코드도 다시 한번 돌아보게 되고
또 다른 분들도 이 과정에서 배우는게 많을테니까요..

...님은 성함이라도 좀 알았으면 하네요.
그래야 나중에 혹시~ offline에서라도 뵈면 인사라도 드릴텐데
ㅋㅋ

익명 사용자의 이미지

음 제가 바이트 오더를 직접 구현한 이유는
이렇습니다..

시스템마다 short나 int의 사이즈가 달라질수가 있어서
단순히 산수로 2바이트 사이즈 정보를 구현하려고 한것이죠.

음.. 2바이트 정수 변수로 형변환을 해서
바이트오더 함수를 사용해서 변환을 하면 간단해 지지만
linux 32비트 머신의 short는 2바이트지만 다른 시스템의
short가 얼마가 될지모르게 되죠.. 그러면,
프리컴파일러 처리를 해야 하는데,
그러느니 그냥 단순히 산수를 하자로 결정을 한것이죠..

익명 사용자의 이미지

안녕하세요~

정훈님 말씀처럼 보안적인 측면이나 튼튼한 서버 만들기에
결점이 있는 코드지요..

처음엔 블럭 모드에 내부 통신함수만 만들었다가
나중에 무한정 대기되는 것때문에
select를 사용한 특정시간내에 i/o가 일어나는 함수도 추가를 했지요

경우에 따라서 무한정 대기가 필요한 경우도 있고,
또, 일정 시간이 지나면 timeout이 필요한 경우도 있구요..
그래서 두가지 함수를 다 만들어 둔것이죠..

넌블럭킹은 이거랑은 별도로 다른 이유 때문에
쓰기는 하는데, 잘 안씁니다.

그리고 고객이 접속하거나 외부로 노출이된 넷트윅 I/O
STX + SIZE + HEAD + DATA + ETX 대략 이런 구조로해서
환형 버퍼를 만들어서 패킷을 받고
뒷단에서는 Reactor 패턴의 응용된 형태로 사용을 합니다.

헤더에는 암호화라던지
암축 패킷 만드는데 필요한 정보들이 들어가고
패킷을 어디로 라우트하는지 뭐 이런 정보들이 들어가게되지요
(어느 서비스 데몬으로 던질것인지...)

패킷가지고 장난치거나, 공격을 당할염려가 있는 코드들은
좀더 튼튼하게 작성을 하게 되지요..

어조가 좀 강해서 따지는듯한 기분이 들었다면 죄송합니다.
저 또한 배우는 입장이라 완전한 지식이 아닙니다.
이렇게 토론으로 하나둘씩 알아가는게 재미라고 생각합니다.

흐흐,, 요지는 내부용 코드라서 라이브러리사 용자를 신뢰한다는
것이고 외부에 노출된 인터페이스는 따로 존재 한다는 것입니다.
정훈님 마지막에 cpu cycle낭비하지 않는 방법이라고 하셨는데
어떤 방법을 말하시는 것인지?? 알고 싶네요..

제가 말한 cpu cycle낭비는 어떤것이냐면

넌블럭킹 특징상, while에 확인 한번에 조건이 아니면 sleep을
하게 되는데 리눅스 같은경우엔 sleep을 하게 되면
스케줄러에서 running queue에서 대기큐로 내려가게 됩니다.
즉 컨텍스트 스위칭이 일어나게 되지요

이렇게 되면 스위칭에 대한 부담과,
스위칭으로 인한 TLB캐쉬같은게 클리어 되기때문에
전체적으로 보면 효율에 문제가 생기더라구요..
(while자체도 그렇구요)

그래서 블럭모드에 select를 선호 하는데
정훈님이 사용하는 방법은 어떤것인지 알고 싶네요.

댓글 달기

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