패킷 파싱의 방법...

3권에서 새로 도입된 네트웍 및 멀티플레이어 프로그로그래밍 섹션을 위한 게시판입니다.

Moderator: 류광

Locked
비회원

Post by 비회원 »

넹 글쿤여.. mastercho님 설명 감사합니다!!
소켓이 일반 파일i/o와 다르다는거를 배웠습니당

근데 recv가 그냥 소켓버퍼에서 사용자버퍼로 옴기는거라해도
소켓버퍼에 락거는 작업은 하겠죠?

제가든 예시를 다시설명하자면
패킷 하나가 헤더 4바이트 바디 6바이트로 구성되어 패킷하나가 총 10바이트이고
이 패킷을 100개를 보낸다고 치면
두번째껀 각각 헤더 호출 100번 바디 호출 100번 해서
200번 이라고 한겁니다

이경우 첫번째 경우라면 1000바이트로 한번에 읽고
읽어온 거를 헤더와 바디로 나누는 파싱을 하면 되는데
이게 더 빠르겟지요



버퍼크기 문제라면 두번째꺼가 좀더 안좋은거 아닌가요

첫번째꺼는 되도록 한번에 많은 패킷크기로 받아서 처리하는 방식이고
(그렇다고 버퍼가 어느정도 찰때까지 기다리는방식은 아님)
두번째꺼는 헤더 만큼받은후 다시 헤더를 보고 바디크기만큼 받아서 처리하는 방식인데
버퍼 비우는 속도는 두번째꺼가 더 느리지 안나요?
ikpil
Posts: 98
Joined: 2008-11-12 21:17

Post by ikpil »

에코서버로 테스트해 보았습니다.

코드는 boost::asio 의 챗팅 서버 코드르 바꾸어, 받은 데이터를 무조건 10만번씩 보냈습니다.

흐름
1. 클라 1개와 서버 1개를 한 컴퓨터에 띄운다.
2. 클라가 다음의 문자열을 서버로 발송한다.

" 가나다라마바사자차카타파하가나다라마바사자차카타파하가나다라마바사자차카타파하가나다라마바사자차카타파하가나다라마바사자차카타파하가나다라마바사자차카타파하가나다라마바사자차카타파하가나다라마바사자차카타파하가나다라마바사자차카타파하"

3. 서버는 다음의 문자열을 받으면 1번씩 끊어서 10만개의 패킷으로 다시 클라에게 발송 한다.

4. 클라는 이 패킷을 받으면 표준 출력을 하여, 패킷이 받을 때 마다 출력 한다.


로 테스트를 했습니다.

결과
무리 없이 모든 내용을 다 출력했습니다.

사견
이 정도가 버퍼 비우는 속도가 느린지 빠른지 모르겠으나. 신경을 쓸 정도는 아니라고 생각 합니다. MMO로 테스트한게 아니기 때문에, 실제로 사용하기 위해선 테스트가 더 필요하나, 존 방식 게임이나 그 이하의 패킷 사용이 필요한 경우라면, 사용해도 문제가 없다고 생각합니다.
비회원

Post by 비회원 »

read recv 한번, data recv 한번 이런식으로 10만번 받고 난 후

걸린 틱과 한번에 다 받아서 스플릿처리하는데 걸리는 틱을 비교해 주셨으면 좋겠습니다...
Zeprod
Posts: 480
Joined: 2006-11-04 16:24
Location: Creaty Networks
Contact:

Post by Zeprod »

비회원 wrote:read recv 한번, data recv 한번 이런식으로 10만번 받고 난 후

걸린 틱과 한번에 다 받아서 스플릿처리하는데 걸리는 틱을 비교해 주셨으면 좋겠습니다...

함수 호출이나 네트워크 버퍼를 읽어오는 작업은 거의 부하가 없다고 봐도 됩니다.

중요한건 버퍼가 가득차버려, 그 이상의 데이터를 받지 못하고 그냥 손실시켜버리는 상태가 없어야 한다는것이죠.
세상이 기다리는 나만의 SHOW!
----------------------------------------------
Zeprod 홈 : http://Zeprod.org
Project. Creaty : http://Creaty.net/
Creaty 게임제작 커뮤니티 : http://Creaty.net/game/
----------------------------------------------
ikpil
Posts: 98
Joined: 2008-11-12 21:17

Post by ikpil »

Zeprod wrote: 함수 호출이나 네트워크 버퍼를 읽어오는 작업은 거의 부하가 없다고 봐도 됩니다.

중요한건 버퍼가 가득차버려, 그 이상의 데이터를 받지 못하고 그냥 손실시켜버리는 상태가 없어야 한다는것이죠.
이 경우엔, TCP 로 한다면, 문제가 없을것 같습니다.
비회원

음 전 두번째 방식이 잘못된거 같은데.. 아닌가요?

Post by 비회원 »

네이버 게임서버카페에서 타고 일루 왔는데 그쪽에선 아무런 답변이 없어서 여기루 왔습니다.

밑에 글은 네이커 카페에서 리플단 글입니다.

음 전 위 말씀하신 방법자체가 이해가 안되는데.. 제가 알고 있기로는 예을들어 헤더가 4바이트 바디가 10바이트라고 했을때 처음 4만큼 WsaRecv()을 걸었다고 했을때 실제 한번에 받을수 있는 데이터는 tcp에서는 4 보다 작을수 있는걸로 알고 있습니다. 또 헤더를 보고 10바이트라는걸 알고 WsaRecv()을 10바이트 건다고 하더라도 같은이유로 10바이트 보다 작을수 있구요.. 실제 받은 데이터가 4바이트 또는 10바이트 보다 작으면 지금 까지 받은 데이터는 링버퍼 같은곳에 쌓아두고 다시 필요한만큼 WsaRecv()을 걸어야 할텐데 그렇다면 결국 위 방법되로 하더라도 큐잉은 필요한거 아닌가요?

한번더 정리 하자면 두 방식의 차이점은 큐잉과정을 없에서 처리방식의 단순화을 꽤하자 인데 위 글처럼 2번째 방식도 결국은 큐잉과정이 필요하지 않냐는게 제 질문입니다. 근데 전 당연히 이런 테클을 거신분이 있을줄 알았는데 카페도 그렇고 여기 gpg도 그렇고 아무도 언급을 안하신거 보니 아무래도 제가 뭔가 놏친게 있을꺼 같네요.. 답변좀 부탁드릴께요
mastercho
Posts: 587
Joined: 2004-05-09 20:37

Post by mastercho »

위에 비회원님 글을 인용하니 글이 제대로 안써지네요
인용은 생략하겠습니다



2번째 경우 링버퍼 같은건 필요 없겠지만
최대 패킷 크기만큼의 버퍼는 필요하겠지요


논의 내용은 링버퍼에 최대한 쌓아두고 파싱을 하는 방식보단 훨씬 간단하게 할수 있다는 점이 핵심이 아닌가 싶습니다
어차피 4바이트 이하로 올수 있는 확률은 거의 없지만 , TCP 설계상 가능은 하겠지요

지적하신 사항은
보통 일반적인 상황인 , 네이글 알고리즘이 켜져 있는 상황에서는 , 패킷이 2개이상 뭉쳐오는 경우도 있기에
원래 패킷보다 작게 잘려 오는 경우는 흔치는 않을것입니다
(TCP 기본 설정은, 최대한 패킷을 모아서 나가겠금 구조가 되어 있기에...)
처음 4만큼 WsaRecv()을 걸었다고 했을때 실제 한번에 받을수 있는 데이터는 tcp에서는 4 보다 작을수 있는걸로 알고 있습니다.
는 거의 본적이 없습니다

보통 짤리는 경우는 패킷 크기가 1024 바이트 이상의 경우 일반적인 이더넷에서는 1024 크기 단위로 잘려서
전송되더군요
[ 실제 환경이 어째튼 , TCP 는 그런것을 가정하지 않겠지만요 ]


물론 이런것을 어플리케이션단에서는 알수는 없습니다
( 전 예전에 윈덤프 같은 로우 레벨을 다룰수 있는 프로그램에서 확인했었던거 같네요 )

결론적으로 믿을만한 사설 랜환경에서는 블럭킹 소켓으로 처리해 아예 큐잉 과정이 필요없게 할수
있을거 같고요 (이렇게, 서버단에 협력하는 프로그램들은 소켓 처리를 단순화 할수도 있지 않을까 싶습니다)
[ 클라이언트에 recv 쓰레드를 두는 경우에도 해당될거 같습니다 ]


아니라면 최소한의 패킷 크기의 버퍼는 두는게 맞는거 같네요
ikpil
Posts: 98
Joined: 2008-11-12 21:17

Re: 음 전 두번째 방식이 잘못된거 같은데.. 아닌가요?

Post by ikpil »

비회원 wrote:실제 한번에 받을수 있는 데이터는 tcp에서는 4 보다 작을수 있는걸로 알고 있습니다.
음..

boost asio 메뉴얼 페이지 중
비동기 read 의 경우 다음의 경우가 발생될때까지 대기 한다고 하네요.

1. 지정한 버퍼가 다 쌓일 때
2. 에러가 발생 되었을 때

그러므로, 4Byte 받겠다고 하면, 4Byte가 지정한 버퍼에 쌓이기 전까지는 핸들러가 호출되지 않는다고 합니다.

해석이 틀릴수도 있어 링크도 함께 첨부 합니다.
http://www.boost.org/doc/libs/1_40_0/do ... load1.html
cchcc
Posts: 4
Joined: 2009-10-20 18:02

Re: 음 전 두번째 방식이 잘못된거 같은데.. 아닌가요?

Post by cchcc »

비회원 wrote:네이버 게임서버카페에서 타고 일루 왔는데 그쪽에선 아무런 답변이 없어서 여기루 왔습니다.

밑에 글은 네이커 카페에서 리플단 글입니다.

음 전 위 말씀하신 방법자체가 이해가 안되는데.. 제가 알고 있기로는 예을들어 헤더가 4바이트 바디가 10바이트라고 했을때 처음 4만큼 WsaRecv()을 걸었다고 했을때 실제 한번에 받을수 있는 데이터는 tcp에서는 4 보다 작을수 있는걸로 알고 있습니다. 또 헤더를 보고 10바이트라는걸 알고 WsaRecv()을 10바이트 건다고 하더라도 같은이유로 10바이트 보다 작을수 있구요.. 실제 받은 데이터가 4바이트 또는 10바이트 보다 작으면 지금 까지 받은 데이터는 링버퍼 같은곳에 쌓아두고 다시 필요한만큼 WsaRecv()을 걸어야 할텐데 그렇다면 결국 위 방법되로 하더라도 큐잉은 필요한거 아닌가요?

한번더 정리 하자면 두 방식의 차이점은 큐잉과정을 없에서 처리방식의 단순화을 꽤하자 인데 위 글처럼 2번째 방식도 결국은 큐잉과정이 필요하지 않냐는게 제 질문입니다. 근데 전 당연히 이런 테클을 거신분이 있을줄 알았는데 카페도 그렇고 여기 gpg도 그렇고 아무도 언급을 안하신거 보니 아무래도 제가 뭔가 ㅤㄴㅗㅊ친게 있을꺼 같네요.. 답변좀 부탁드릴께요

물론 recv했더니 원하는 바이트만큼 안올경우가 있습니다.

iocp의 경우라면 처음부터 4바이트로 recv 오버랩을 걸어두면 4바이트 받기 전까지는
워커스레드에서 i/o핸들러호출까지 이어지지 않으므로 전혀 신경쓸부분이 아니고

그외 컴플리션 포트 방식이 아닌 다른방식(epoll,select등) 에도 큐잉할 필요없이
덜받앗으면 덜받은 만큼 반복문내에서 recv를 더 호출해주는 방식도 있습니다.


두번째꺼는 첫번째꺼에 비해 recv호출수도 맣고
iocp라면 recv오버랩도 소켓당 1개밖에 걸지 못하고
대신 버퍼큐질 하는게 없으니 구현이 좀더 쉬운거 빼고는 장점을 모르겠네요
softpark
Posts: 4
Joined: 2009-11-20 12:20

Post by softpark »

위와 같은 구조로 서버단 패킷을 처리 하면, 생길수 있는 문제는 어떤게 있을가요?
또는 실제 위와 같은 방식으로 패킷처리를 하고 계시는 분들이 계시면, 그 분들의 의견도 들어보고 싶습니다.
요것이 질문이신거 같은데..

제 생각엔 두가지 방법 다 문제는 없습니다..

단.. 속도 차이가 많이 납니다. 둘다 프로파일링을 많이 해보았으며, header 와 body를 분리한 처리 방법을 버릴정도로, 큰 속도 차입니다.

두가지 다 구현해 놓고.. 현재는 header와 body를 분리한 방식은 사용하지 않고 있습니다..
Locked