[질문] 사용자 패킷을 만들어 쓸때 문제점...

mastercho의 이미지

예를 들어 사용자 패킷 Head , Body로 나누고

헤더를 읽은다음 바디를 판단해 읽는거라고 칩니다

소켓은 블럭킹 소켓이고요

패킷을 읽는 방식은

while 문동안 head만큼 recv를 한다음

head를 파악해서 body를 다시 while으로 읽어내고요

그런데 해커가 만약 1바이트만 보내고 만다면

while문에서 recv에서 블럭을 당할텐데요

그렇다면 poller를 사용하는 그 쓰레드는 중지 될테고

문제가 될거 같은데

해결할 방법이 없을까요?

운형의 이미지

tcp경우라면 recv시작동시에 스레드 하나 만들어 타이머 기능을 부여하면 될거 같습니다. 일정시간 경과후 커낵션이 유효한가를 판단해서 서버측에서 연결을 끊고 버퍼를 비우는 작업을 해주셔도될 것 같구요.

방화벽에서도 이상하리 만큼 작은 패킷, 혹은 지나치게 많이 단편화 조각은 걸러 낼수 있는 걸로 알고 있습니다.

유사한 예로 syn패킷만 날리고 ack는 안날리는 크래킹 시도도 있습니다. 이 경우 방화벽없이는 제어가 어려운데, 이경우는 아닌거 같군요.

Do you think that's the air you are breathing now?

옥정훈의 이미지

단순 타이머 역할을 하기 위해 recv() 할 때 마다 쓰레드를 만든다는 건
오버헤드가 커서 성능이 말이 아니겠네요.
더군다나 타이머 역할을 위해 생성된 쓰레드가 타임아웃이 되었을 때
어떤 방법으로 recv()에서 blocking 중인 쓰레드를 깨울지에 대한
방법이 없는 건 마찬가지이고요. 후후

질문하신 내용은 스티븐스의 책 13장에
3가지 방법이 예제까지 곁들여 상세히 제시되어 있습니다.
1. alarm()을 이용한다.
2. select()를 이용한다.
3. 소켓옵션 SO_RCVTIMEO를 이용한다.

제가 조금만 더 설명을 덧붙이자면,

1번의 방법의 예로 스티븐스는 connect()를 이용했는데
리눅스의 맨페이지에서 보면 아시겠지만 (man 2 connect)
connect()는 EINTR이라는 에러를 리턴하지 않습니다.
따라서 스티븐스가 제시한 1번 방법이 connect()의 경우
리눅스에서는 동작하지 않습니다.
하지만 man 2 recv를 보면
recv()는 EINTR이라는 에러를 리턴합니다.
따라서 질문하신 분의 용도, 즉 recv()의 경우에는 1번도 사용이 가능합니다. 그리고 가장 단순하면서도 효율적인 방법이 되겠네요.
따라서 1번 방법을 blocking IO에 사용하기 위해서는
해당 OS에서 제대로 동작할지를 맨페이지를 이용해 꼼꼼이 살펴 보셔야 합니다.

2번 방법은 모든 시스템에서 적용 가능합니다.

3번 방법은 스티븐스도 말했듯이 모든 시스템에서 구현되어 있지 않습니다.
1번과 마찬가지로 적용여부를 미리 검토해야 합니다.

jolasen의 이미지

왜 head와 body를 따로 읽는지를 알아야 할듯 하네요..
보통 client가 보낸만큼 다 읽어서 완전한 패킷인지 검사를 해서 다 보냈을때
head에 따라 처리 하는게 일반적이지 않나 하는데요..

xjiwoox의 이미지

Quote:
왜 head와 body를 따로 읽는지를 알아야 할듯 하네요..
보통 client가 보낸만큼 다 읽어서 완전한 패킷인지 검사를 해서 다 보냈을때
head에 따라 처리 하는게 일반적이지 않나 하는데요..

client에서 보내는 패킷이 항상 일정한 크기라고 확신할 수 없기 때문입니다.
(client와 server를 개발할 때 사전에 일정 크기의 패킷만을 주고 받기로
약속한 경우는 예외가 됩니다만...)
TCP/IP socket의 경우 client가 보낸 패킷이 한 번에 recv 된다는 보장이
없기 때문에 header(fixed size..)정보를 두어서 전체 패킷 사이즈라던가 하는
정보를 구해 패킷 컨트롤을 하는 것이죠.

물론, header나 body의 구분 없이 패킷의 시작과 종료를 나타내는 매직넘버
필드를 두어서 처리를 할 수도 있지만 실제 데이터 부분이 이 매직넘버와 같은
값을 갖지 않는다는 보장을 하기도 어렵고, 특수한 데이터 타입이라 같은 값을
가질 일이 없다고 하더라도 나뉘어 도착하는 패킷을 recv할 때마다 합쳐서
전체 패킷이 다 도착했는지 여부를 판단하는 처리작업(파싱이나 코드검사,
사이즈검사 등의 부수적인 작업들...)을 하는 것은 확실히 효율적이지는 않기
때문이죠.

s(˘∼˘*)z,·´″"`°³о$ √(´∀`√)... (˘ヘ˘ㆀ)a

ssehoony의 이미지

버클리 소켓 라이블러리의 리시브 함수에는 파라미터로 timeout 값도 있는데
혹시 그거 모르고 계신것 아닌가요?
블러킹 모드일때 timeout 값을 셋팅해 놓으면 그 시간이 넘어가면
블러킹 모드에서 빠져 나옵니다.

흠... recv 에는 없군여 timeout을 파라미터로 넘기는거요 ^^ 죄송
select 같은 것과 헷갈렸네요.

옥정훈의 이미지

devilhero wrote:
버클리 소켓 라이블러리의 리시브 함수에는 파라미터로 timeout 값도 있는데
혹시 그거 모르고 계신것 아닌가요?
블러킹 모드일때 timeout 값을 셋팅해 놓으면 그 시간이 넘어가면
블러킹 모드에서 빠져 나옵니다.

맨페이지에 나온 recv()의 prototype은
int recv(int s, void *buf, size_t len, int flags);
입니다.
여기 어디에도 timeout을 인자로 받을 수 없습니다.
flags를 혹시 오해하신 거라면 flags는 다음과 같은 값을 가지게 되어 있습니다.
MSG_OOB, MSG_PEEK, MSG_WAITALL, MSG_NOSIGANL,
MSG_TRUNC, MSG_ERRQUEUE, MSG_EOR, MSG_CTRUNC,
MSG_DONTWAIT입니다.

결국 recv()에 timeout 값을 인자로 넘겨 줄 수 있는 방법은 없습니다.
혹시 setsockopt()를 이용하는 방법을 말씀하신 건가요?
그건 위의 제 답글에 3번에 설명되어 있는 내용입니다.

말씀하신, recv()에 timeout 값을 인자로 줄 수 있는
제가 모르는 기발한 방법이 있다면 공유하시죠... ^^

jolasen의 이미지

xjiwoox wrote:
Quote:
왜 head와 body를 따로 읽는지를 알아야 할듯 하네요..
보통 client가 보낸만큼 다 읽어서 완전한 패킷인지 검사를 해서 다 보냈을때
head에 따라 처리 하는게 일반적이지 않나 하는데요..

client에서 보내는 패킷이 항상 일정한 크기라고 확신할 수 없기 때문입니다.
(client와 server를 개발할 때 사전에 일정 크기의 패킷만을 주고 받기로
약속한 경우는 예외가 됩니다만...)
TCP/IP socket의 경우 client가 보낸 패킷이 한 번에 recv 된다는 보장이
없기 때문에 header(fixed size..)정보를 두어서 전체 패킷 사이즈라던가 하는
정보를 구해 패킷 컨트롤을 하는 것이죠.

물론, header나 body의 구분 없이 패킷의 시작과 종료를 나타내는 매직넘버
필드를 두어서 처리를 할 수도 있지만 실제 데이터 부분이 이 매직넘버와 같은
값을 갖지 않는다는 보장을 하기도 어렵고, 특수한 데이터 타입이라 같은 값을
가질 일이 없다고 하더라도 나뉘어 도착하는 패킷을 recv할 때마다 합쳐서
전체 패킷이 다 도착했는지 여부를 판단하는 처리작업(파싱이나 코드검사,
사이즈검사 등의 부수적인 작업들...)을 하는 것은 확실히 효율적이지는 않기
때문이죠.


제글 3줄이 xjiwoox님께서 설명하신걸 간단하게 해놓은거 같은데요..-_-;;
옥정훈의 이미지

Quote:
왜 head와 body를 따로 읽는지를 알아야 할듯 하네요..
보통 client가 보낸만큼 다 읽어서 완전한 패킷인지 검사를 해서 다 보냈을때
head에 따라 처리 하는게 일반적이지 않나 하는데요..

두 가지 오류가 있습니다.

1. 최초 질문하신 분의 질문의 요지는
head와 body를 따로 읽을 것이냐 한번에 읽도록 할 것이냐가 아니라
클라이언트가 보낸 데이터를 recv() 한번 호출로 다 받지 못할 경우
발생할 수 있는 취약성에 어떻게 대처할 것이냐입니다.

2. "클라이언트가 보낸만큼 다 읽어서 완전한 패킷인지 검사를 해서"
라고 하셨는데, 검사해 보니 완전한 패킷이 아닐 경우 어떻게 해야 합니까?
두 가지 방법이 있을 겁니다.
첫째, 데이터가 다 오지 않았을 수 있으므로 recv()를 한 번 더 호출해서 데이터를 마저 받는다. 이렇게 되면 다시 원래의 주제로 돌아가게 됩니다.
둘째, 공격의 가능성이 있으므로 버린다. 만일 정상 패킷이고
다만 길이가 클 뿐이라면 loss된 데이터를 어떻게 처리하시렵니까.

mastercho의 이미지

일단 제가 계발한 방법이 있긴한데

실무에서는 논블럭으로 따로 버퍼를 두어 헤더 만큼 받았는지

체크하고 받았으면 바디 싸이즈를 체크하고

받지 못했으면 받은 만큼만 버퍼에 저장해 두고 리턴하고

다시 poll에서 자료가 올때까지 기다리고 그런 방식을 취하더군요

근데 이방법은 따로 버퍼를 두어야 한다는 단점이 있고

버퍼에 따른 상당히 많은 조작을 필요로 하네요

좀더 산듯한 방법이 없는지 궁금하네요

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

익명 사용자의 이미지

그냥 글 감시하다가 적어봅니다.

일단 이거는 별로 추천방법은 아니지만 이런것도 있어요.

recv / recvftom에 보시면 flags에서 MSG_PEEK라는게 있어요.
이것은 실제로 읽어서 socket buffer를 비우지 않고
복사본을 한번 빼와보는 것이거든요.
즉, recv에서 MSG_PEEK로 읽으면 맨날 첫 바이트는 같아요.
그리고 ioctl로 FIONREAD를 함께 이용하면 블럭도 안되고
원하는거 읽었다가 안빼고 다음으로 넘어가면 그만이거든요.

자세한것은 "man recvfrom" 해보시면 간략한 설명이므로
여러번 반복해서 읽어보면 이해가 될거예요. 저는 이거 하루종일
반복해서 읽다가 알게 된겁니다.

mastercho의 이미지

RCVTIMEO 같은 옵션이나

SO_RCVLOWAT 같은 옵션을 모든 플레폼에서 지원되는

확인할 방법이 없을까요?

저 같은 경우 리눅스 레드헷 8.0과 SunOS 5.8에서는 확실히 지원되던데

그리고 BSD 계열은 분명 지원이 될테고요 [BSD에서 추가된 내용]

SVR4 계열에만 문서화가 되지 않았다고 봤는데

SVR4 계열로 다른 OS가 뭐가 있을까요? 위에 말한 저 2종류 말고

테스트좀 해주실수 없는지요?

#include <sys/socket.h>에
저 메크로 상수가 정의 되어 있는지만 확인하면 되거든요

이코드만 컴파일 되면 됩니다

#include <sys/socket.h>
#include <stdio.h>

int main()
{
printf("%d",SO_RCVLOWAT);
printf(" %d",SO_RCVTIMEO);
}

부탁드립니다

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

mastercho의 이미지

참 위에 select문을 쓰시라는분

말이 안되는게

select는 1바이트만 차도 리턴됩니다

따라서 헤더가 5바이트라면

5바이트를 받도록 recv가 while루프를 돌텐데

나머지 4바이트를 받지 못해

select 로 해도 역시

블럭당하죠

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

옥정훈의 이미지

mastercho wrote:
참 위에 select문을 쓰시라는분

말이 안되는게

select는 1바이트만 차도 리턴됩니다

따라서 헤더가 5바이트라면

5바이트를 받도록 recv가 while루프를 돌텐데

나머지 4바이트를 받지 못해

select 로 해도 역시

블럭당하죠

스티븐스의 책 13장을 보세요. Figure 13.3이요.
select()의 마지막 인자가 무슨 용도인지까지 설명을 드릴 걸 그랬나 보군요.
질문에 답할 때 백지 상태부터 다 설명할 수도 없고
이 정도면 이해하겠지 나름대로 선을 긋고 설명을 시작할 수 밖에 없는데
질문하신 분의 수준을 제가 너무 높게 잡았나 봅니다.

그래서 어떤 책의 몇장을 보시라고까지 말씀 드린건데,
그조차도 보지도 않고 말이 안된다 하시니...
그리고 select()를 사용하는 방법을 제가 생각해 낸 것도 아니고
스티븐스의 책에 있는 내용이라고까지 말씀 드렸는데
어떤 자신감으로 알아 보지도 않고 말도 안된다 하신 건지...

스티븐스의 책 13장을 꼭 좀 공부하신 다음에
왜 말도 안되는 건지를 꼭 좀 밝혀 주십시오.

제가 지금 감정이 좀 격해져서 감정적인 말 좀 더 하겠습니다.
Blocking IO에서의 이런 처리 문제는 고급테크닉도 아니고 기본적인 내용인데
이를 두고 님과 맞느니 틀리느니 하고 논쟁을 한다는게... 참...

mastercho의 이미지

삭제

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

옥정훈의 이미지

아니 그럼 스티븐스의 책을 봤는데도 이해를 못하신건가요?
예제까지 보신 것 같이 말씀을 하시니 정말 보긴 보신 거 같은데...

저로서는 좀 난감한 상황이 되어 버렸습니다.
책을 읽었으면 이해할 수 있는 정도는 되어야 논쟁을 해도 할텐데...
더 이상 설명을 하기가 어렵게 되어 버렸습니다.

그럼 이렇게 접근해 봅시다.
님께서 하신 말씀들에 대해서 제가 거꾸로 질문하는 식으로 하겠습니다.
이번에는 생각도 좀 해 보시길...

mastercho wrote:

타이머를 둔다고 해결될 일이 아니라서 하는 말이 아닌가요?

님께서는 그래서 SO_RCVTIMEO를 쓰기로 결정하신 거죠?
SO_RCVTIMEO를 사용하려면 timeout 값을 이용해야 하지 않습니까?
그 값을 select()의 마지막 인자로 사용한다면
SO_RCVTIMEO와 다를 게 전혀 없지 않습니까?
님은 분명 timeout으로 해결할 수 없다고 말씀하시면서
timeout을 이용하는 SO_RCVTIMEO를 사용하기로 결정하신 건가요?

아직도 이해를 못하신다면 이것도 생각해 봅시다.

mastercho wrote:

따라서 select는 1바이트만 소켓에 차도
리턴은 되지만 전체 패킷을 다 읽을때까지
while루프를 돌면서 recv를 하는겁니다


SO_RCVTIMEO를 이용하는 경우에도 역시
1바이트만 소켓에 차도
리턴은 되지만 전체 패킷을 다 읽을때까지
while루프를 돌면서 recv를 하지 않습니까?

그럼 왜 SO_RCVTIMEO는 되고 select()는 안 되는 겁니까?
mastercho의 이미지

삭제

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

펑키의 이미지

두분 모두 자제하시는것이....

안녕하세요. 제 생각에는 두분다 말씀 중에 약간의 미묘한 오해 살만한 문구가 들어간듯 합니다. 그냥 넘겨버리시는게 어떠실런지요.? 내가 맞고 당신이 틀린것은 별로 없을듯 합니다.

제 생각에는
1. SELECT에서 감시 가능한것은 읽을수 있는지 쓸수 있는지 정도입니다. 따라서 RECV() 이벤트 발생 정도만 나타내지 실제 RECV()중에 특정한 사이즈를 받다가 중간에 블락 걸리는것은 감지 하지 못할겁니다. 즉, 타임아웃 시간동안에 읽거나 쓸수 있는 이벤트가 발생하는지만 감지하지 이미 읽는 이벤트가 발생한 이후에 블락이 걸리는건 SELECT 타임아웃이 아무런 역할을 못할겁니다.

2. 소켓 옵션을 사용해 보는건 어떨까요.? 이것도 답이 될수 있을듯 싶습니다.

3. 긍극적으로는 넌블락으로 가는게 답이 되지 않을까요.? 물론 처리 하기 조금 골치 아파질것이지만 어짜피 접속이라던지 이런것 처리 할려면 넌블락으로 가야 할테구 말이죠. 시스템적으로는 넌블락모드를 만들고 비즈니스 프로세서적으로 블락 모드를 가는건 어떨까요.?

이렇게 생각해보는건 어떨까요.? 즐거운 하루 되세요.

옥정훈의 이미지

mastercho wrote:

select 타이머는 단지 그 시간동안 소켓의 이벤트가 없으면 그냥 리턴하는 정도의 역활입니다
select에 타이머를 두는거와
recv에 타이머가 걸리는거와 어떻게 같은지 도무지 이해가 안되는군요

후후... 그런거였군요...
이제서야 님이 왜 select()로는 안 된다고 일관되게 주장하시는지 알겠습니다.
무엇때문에 그렇게 헤매셨는지는 알았지만
어디서부터 설명을 해야 할지 막막하긴 마찬가지입니다.

제 생각에 님에게는 말로 설명하는 것에 무리가 있다 판단되어지므로
select()를 이용한 recv()를 wrapping한 Recv()를 하나 만들테니
직접 돌려 보십시오.
(스티븐스 책에 있는 예제가 그렇게 이해하기 힘들었나...)

Quote:
/*
* DESCRIPTION:
* Recv() returns only
* when the number of bytes received is same as len,
* when timeout is expired
* or when an error is occurred.
*
* RETURN VALUE:
* This call returns the number of bytes received,
* or -1 if an error occurred or timeout is expired.
*/
int Recv(int s, void *buf, size_t len, int flags, int timeout)
{
int tot = len;
int rcv=0, ret;

while(1)
{
fd_set fdset;
struct timeval tv;

if(tot == 0)
break;

FD_ZERO(&fdset);
FD_SET(s, &fdset);
tv.tv_sec = timeout;
tv.tv_usec = 0;

if((ret=select(s+1, NULL, &fdset, NULL, &tv)) == 0)
return -1; // timeout is expired
else if(ret < 0)
{
if(errno == EINTR)
continue;

}

if((ret=recv(s, &data[rcv], tot, flags)) < 0)
{
if(errno == EINTR)
continue;

return -1;
}
else if(n == 0)
break;

tot -= n;
rcv += n;
}

return rcv;
}

이 코드는 문제의 소지가 있습니다.
recv() 가 0 또는 -1을 리턴할 때의 처리 부분이 바로 문제의 부분이지만
지금의 주제와는 무관하므로 그냥 올립니다.
이것은 wrapper를 구현하는 사람의 정책의 문제이기 때문입니다.
바로 이런 문제 때문에 스티븐스는
위의 Recv()와 같이 recv()와 select()를 함께 두지 않고
select()로 확인만 하는 readable_timeo()라는 함수를 만들었겠지요.

본 주제와 무관하지만 굵은 글씨체로 씌여 있는 부분을 잠시 설명하겠습니다.
blocking IO에서 시그널 발생시 해당 콜은 errno를 EINTR로 셋하고
-1을 리턴하게 되어 있습니다. 하지만 이는 실제 작업과 무관하므로 무시하고
다시 루프를 돌게 되어 있는 것입니다.
스티븐스의 책에 자세히 나와 있습니다.
제가 처음 글에서 1번으로 말씀 드린 alarm()을 이용하는 방법이 바로 이에 해당되는 것입니다.

본 주제와 무관하지만 색깔을 달리 칠한 부분을 잠시 설명하겠습니다.
select()의 리눅스에서만 존재하는 특성으로
select()는 타임아웃이 안 된 상태에서 리턴을 할 경우 마지막 인자의 값이
최초 지정한 값과 달라지게 되어 있습니다.
sleep을 다 하지 못하고 남은 값이 설정되어 리턴되게 되어 있습니다.
따라서 select()를 루프를 돌릴 때에는 매번 콜하기 전에 반드시
초기화 시켜 주어야 합니다.
스티븐스의 책과 맨페이지에 잘 나와 있습니다.

이걸 보고도 님이 이해를 못하시겠다면...
생각만 해도 아찔하네요...
부디 깊이 깊이 생각해 보시고
공부도 더 하시고...
아니면 직접 저걸 돌려 보시던지...

mastercho의 이미지

삭제

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

mastercho의 이미지

삭제

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

옥정훈의 이미지

mastercho wrote:

그부분에 대해서 오해를 한거 같군요
님이 계속 주장해온 select를 사용한다?는 의미가 저런 뜻이 있었는지 미쳐 몰랐습니다

이제는 이해를 하신 거군요. 다행입니다.
솔직이 이걸 보고도 계속 억지 주장을 하시면 전 포기하려고 했습니다.
역시 코드를 직접 봐야만 이해하시는군요...

mastercho wrote:

아마도 제 추측이지만 , 정상적인 사람이라면 님의 의도를 저렇게 파악할수밖에 없게 말씀하신거 같은데요?

제 의도요?
전 스티븐스 책의 예제를 좀 보라고, 생각을 좀 해 보라고
누누이 말씀 드렸습니다.
정상적인 사람은 이해를 못한다고요?
정상적인 사람은 스티븐스의 책을 이해 못한다는 말입니까?
전 저걸 혼자 알아냈겠습니까?
전 스티븐스의 책 13장을 보고 알았습니다.
제가 비정상적인 사람입니까?
제 예제와 스티븐스의 예제가 뭐가 다릅니까?
스티븐스는 select()만을 wrapping 했고
전 다만 select()와 recv()를 연동만 했을 뿐입니다. 딱 1단계 아닙니까?

mastercho wrote:

또한 위 코드를 보면서 생각한건데
... 제가 이미 말하지 않았나요?
스티븐스책 에 나온 그부분에 [위에 나온거와 같은] 관해서는 논블럭 소켓 처리보다 나을게 전혀 없었던거 같다고?
그 소리를 했다는건 저 이야기가 중요한게 아니란걸 의미했다는걸
님도 알아먹으셨을거 같은데 무슨 심보로 ... 계속해서 억지를 부리는지 몰겠네요
그래서 위해 논블럭보다 깔끔한 처리가 없을까요?라고 물었죠?

아니 난데없이 이건 또 무슨 이야기입니까?
님이 select()를 쓴다는 건 말도 안된다로 우리의 긴 이야기가 시작되었습니다.
전 그걸 된다고 계속 주장했던 거구요.
그런데 위의 말은 select()가 되냐 안되냐가 중요한게 아니라
더 깔끔한 방법이 없느냐는 이야기를 하고 있었다는 것 처럼 들리네요.
어디로 빠져 나가십니까?
우리(?)의 주제는 성능 좋은 구현이 아니라
select()가 정말 말도 안되는 것이냐였습니다.

님이 애초에 select()로 처리하는 방법이 잘 이해가 안 가니 좀 더 설명해 달라고 말씀하셨다면 저 역시도 감정이 상하지 않았을 겁니다.
그런데 말도 안된다라고 해 버리시니 님 같으면 좋은 감정이 되겠습니까?

mastercho wrote:

역시 인터넷에서는 조심해야겠군요 허참 ... 뭐한테 물린기분이라고 해야하는지

그렇습니다. 조심해야 합니다. 님은 앞으로도 계속 조심하십시오.
모르는 게 왜 잘못이겠습니까.
다 아는 사람이 어디 있겠습니까.
서로 공부하면서 배우는 거죠.
그러니 말을 함부로 하면 안된다는 겁니다.
님께서
"select()를 사용하는 것은 말도 안된다"
라고 말씀을 하셔서 우리가 여기까지 온 것 아닙니까?
모르면 공부를 하십시오.
그래도 모르겠으면 물어 보십시오.
공부도 안하고 물어보시기에 어딜 공부하라고 알려만 드렸는데
제대로 이해도 안 한 상태에서 말도 안된다고 하시니...
봐도 모를 수도 있을 겁니다. 그러면 예의를 갖추어 다시 질문하십시오.
옥정훈의 이미지

mastercho wrote:
님이 써놓은 글입니다
이글을 읽고 님이 제시하신 위 코드처럼 상상하지 못하고
의문을 가진 제가 허접이긴 하지만 , 그렇다면 이 세상에는
님보다 뛰어난 허접도 상당히 많을거 같다는 생각이 드는군요

저... mastercho님...
제가 처음 작성하였던 글에서
3가지 방법의 구체적인 설명을 어디 한곳이라도 했습니까?
그 구체적인 내용을 이 게시판에 다 써야 합니까?
책에서만도 6페이지가 되는 내용을 말입니까?
더군다나 님의 수준도 모르는 상태에서 어디부터 설명을 해야겠습니까?
1번 alarm()을 이용한 방법을 설명하기 위해 어디서부터 설명을 해야 할까요?
시그널의 개념부터 설명할까요?
그래서 전 스티븐스 책 13장에 있다는 말로 대신하지 않았습니까?
다만 그 책에는 없지만,
제가 알고 있는 주의해야 할 내용만을 1번에 추가해서 설명한 것입니다.

도움을 드렸는데도 끝까지 저를 비아냥거리시는 걸 보고
마음 같아서는 어떻게든 사과를 받을 때까지 계속 늘어지고 싶지만
님이 어쩌다 실수하신 거라 생각하고 참겠습니다.
그리고 어찌 되었든 님이 내용을 결국 이해를 하셨다니
마음이 좀 가라앉기도 하였습니다.
무작정 억지를 부리는 사람은 아니구나 하는 생각에서요...

mastercho의 이미지

삭제

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

옥정훈의 이미지

휴~~ 정말 끝까지 실망이네요...

잠시 담배를 한 대 피우면서
제가 뭘 잘못했나를 분석해 봐야 하겠습니다.

질문에 답한것,
초보자가 쉽게 알아 들을 수 있도록
게시판이 넘쳐 나도록 책 6페이지에 해당하는 내용을 직접 적지 않고
게으른 사람이 책을 직접 보도록 책제목과 chapter만을 알려 준 것,
말도 안된다는 대답에 감정이 상한 것,
부연 설명에도 전혀 이해를 못해서 코딩까지 직접 해서 이해시킨 것...

잘 모르겠습니다.
예, 그냥 제가 접겠습니다.
근데 왜 이리 우울하고 씁쓸할까...
너무 바빠서 거의 반년 만에 다시 찾아온 kldp 게시판인데...

mastercho의 이미지

옥정훈님이 악의를 가지고 그런건 아니라고 판단했습니다

어째튼 제 목적과 상관없는 말씀을 계속하시길레

거친 소리가 나온거 같네요

감정이 섞인 말은 지우도록 하겠습니다 [삭제 버튼이 없군요]

그럼

승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스

옥정훈의 이미지

mastercho wrote:

어째튼 제 목적과 상관없는 말씀을 계속하시길레

진심입니까?
저더러 이것까지 참으라는 겁니까?

mach의 이미지

magic number를 사용하세요.

다음 2가지를 사용하셔서 어느정도 목적하시는 바를 달성하실수 있을듯합니다.

1) 헤더부분에 magic number를 둔다.
 - 님이 개발하신 프로토콜을 구분(식별)할 수 있는 매직번호를 둔다
 - 예를 들어, 헤더의 처음시작은 0xfffefdfc라는 매직번호로 시작하도록 한다던지, 아니면 연결후 sequence를 프로토콜에 부여 처음에는 0x00000000, 다음은 0x00000001,.... 이런식으로하는 방법도 있습니다.
2) ticket을 사용한다.
 - 클라이언트 접속
 - 서버는 티켓을(고유번호) 클라이언트에게 전달
 - 클라이언트는 티켓을 헤더에 포함하여 서버에게 요청전달
 - 서버는 티켓을 검사하고, 요청을 받은 후 처리하여 결과전달
3) timeout을 검사
 - 매직번호와 ticket만으로 전체를 감지하기는 어렵고, 역시 타임아웃을 검사하는 방법이 같이 사용되어야 할것입니다.
 - timeout을 검사하는 방법론은 너무도 많이 논의가 되었네요.

------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.

펑키의 이미지

딱 12시간을 두분이 말씀 하신것 같네요.

은빛연어의 이미지

구현은 만드는 사람 맘이겠쪄~~ ^^*
저는 예전에 이렇게 구현했습니다... 원래 프로토콜이라는게 약속이기때문에 패킷이 틀려지면 해당 패킷이 쓰레기가 되졈..
첫 octet에 패킷의 length가 들어 있고 그 이후에 user-data가 들어 있다면 다음과 같이 receive 함수를 만들수 있습니다.

(TCP죠? UDP는 안되는거 아시졈.. ^^*)
1. 먼저 1octet를 읽어들인다. (참고 : unsigned char인 1 octet으로 표현가능한 범위는 255-->당근 user-data부분의 최대 길이가 255겠졈.)
2. 읽어들인 1octet의 유효성을 검사한다.
3. 나머지 user-data부분을 길이만큼 읽어 들인다.
4. 블럭을 걸린경우를 위해서 recv할때 timer를 이용한 에러 리턴 함수를 추가한다.

이런식으로 예전에 구현해서 아직 상용에서 문제없이 돌아가고 있슴도ㅑ.. ^^*
참고되시길...

댓글 달기

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