2012-08-03 3 views
0

제목에서 내 문제를 설명하는 방법을 잘 모르지만 내 문제를 자세히 설명하려고합니다.비동기 TCP 소켓 바이트 합치기

기본적으로 저는 P2P가 아닌 모든 사용자가 IRC와 비슷한 중앙 서버에 연결하는 채팅을 코딩하고 있습니다. 연결은 비동기 적이며 거의 완벽하게 작동합니다. 주된 문제는 한 번에 한 사용자 (또는 한 사용자의 서버)로 많은 양의 데이터를 보내면 바이트가 병합되어 오류가 발생할 수 있다는 것입니다. 데이터의 나머지 부분 앞에 데이터의 길이를 포함하는 4 바이트 헤더를 추가하여이 접근했습니다. 여전히 바이트는 병합되는 것처럼 보입니다. 나도 설정하려고 시도했습니다 NoDelay ~ 사실DontFragment ~ 거짓; 여전히 작동하지 않습니다.

바이트를 병합 할 때 첫 번째 바이트 만 처리 한 다음 나머지는 아무 것도하지 않는 것이 문제라고 생각합니다. 이 문제에 접근하는 가장 좋은 방법은 무엇입니까? 그들은 스트림라고 부르는 이유이다 http://pastebin.com/f0MvjHag

+1

'이 문제에 접근하는 가장 좋은 방법은 무엇입니까?'귀하의 코드가 도움이 될 것입니다. –

+0

@orzechowskid 물론. op의 수신 콜백 소스에 대한 링크를 추가했습니다. – Fetrix

+0

에 있으므로 질문에 코드를 추가하는 것이 관례입니다. 코드가 너무 길면 자체적으로 포함 된 짧은 예제로 작업하십시오. – spender

답변

2

:

콜백 코드를받을 수 있습니다. 한쪽 끝에 바이트를 넣고 TCP는 상대방에서 누락되거나 중복되지 않는 동일한 순서로 나오는 것을 보장합니다. 한 바이트보다 큰 것이 문제입니다.

헤더를 보유하려면 버퍼에 충분한 바이트를 축적해야합니다. 그런 다음이를 해석하고 추가 바이트 처리를 시작하십시오. 다음 헤더를 시작하는 데 약간의 문제가있을 수 있습니다.

이는 정상적인 동작입니다. 응용 프로그램에서 데이터를받지 못하면 시스템에서 버퍼링합니다. 다음에 요청할 때 사용 가능한 데이터를 전달하려고 시도합니다. 반면에, 큰 쓰기는 적절한 프레임 크기를 지원하지 않는 연결을 통해 이동할 수 있습니다. 그들은 필요에 따라 나누어지고, 결국은 관료들과 멍청이들에 도착할 것입니다.

+0

그래서 가장 좋은 해결책은 다음과 같습니다 : 버퍼 읽기, 데이터 길이 가져 오기, 데이터 길이 + 4 = 읽기 길이 검사, 읽기 길이> 데이터 길이 + 4 버퍼의 나머지 처리? 내가 분명히했는지 확신 할 수 없다. – Fetrix

+0

상태 시스템을 사용하면 헤더와 본문을 번갈아 사용할 때이 작업을 쉽게 수행 할 수 있습니다. 받은 데이터를 버퍼에 계속 추가하십시오. 읽기가 완료 될 때마다 : 버퍼 길이> = 헤더 길이이면 프로세스 헤더.남아있는 버퍼 길이> = 메시지 본문 길이 인 경우 메시지를 처리합니다. 그리고 이미 다음 헤더가 있는지 확인하십시오. (Lather, rinse, repeat.) – HABO

+1

당신의 제안을 시도하기 전에, 나는 다른 접근법을 시도했다. 먼저 4 바이트를 비동기 적으로 읽습니다. 분명히 데이터의 길이가 포함되어 있습니다. 그런 다음 모든 데이터가 수신 될 때까지 읽는 루프를 수행합니다. 모든 데이터를 스트림에 쓰고 데이터를받은 후에 처리합니다. 그런 다음 4 바이트를 다시 읽고 읽습니다. 이 접근법에 대해 어떻게 생각하십니까? – Fetrix

1

일반적으로 두 개 이상의 데이터 패킷이 가까운 간격으로 전송 될 때 발생합니다. 최근에이 문제가 나 자신에게 있었고, 내가 해결 한 방법은 분리 열쇠였습니다. 그런 다음 각 메시지를 토큰화할 수 있습니다. 예를 들어, 내가 한 것처럼 각 메시지의 끝 부분에 ASCII 문자 # 4 (전송 끝 문자)를 추가 할 수 있습니다.

Write("Message1" + ((char)4).ToString()) 
Write("Message2" + ((char)4).ToString()) 

그런 다음 클라이언트가 데이터를 수신하면 수신 된 데이터를 반복 할 수 있습니다. 그 특수 문자를 발견하면, 그것은 하나의 메시지의 끝이고 (아마) 새로운 메시지의 시작임을 알게됩니다.

"Message1(EOT char)Message2(EOT char)" 

은 ASCII 문자를 사용하는 것보다 쉽게 ​​작업 할 수 있습니다.

+0

이것은 유효한 (및 상당히 일반적인) 기술이지만, EOT 문자가 스트림에 나타날 수있는 경우 문제가 있습니다. 그럴 경우 EOT 문자와 이스케이프 문자를 이스케이프 처리해야합니다. – Gabe

+0

그래, 내가 쓴 것은 그것을 벗어난다. 아마도 EOT char가 공통적으로 사용되는 경우는 드물 긴하지만 (필자의 사용법에서는) 중요한 점을 언급했을 것입니다. – Yasahiro