문제

이건 내 분기 중 하나야 다른 질문.원한다면 읽어보되 꼭 그럴 필요는 없습니다.

기본적으로 대용량 메시지에서 C#의 BeginReceive()를 효과적으로 사용하려면 (a) 먼저 패킷 길이를 읽은 다음 정확히 그 만큼의 바이트를 읽거나 (b) 패킷 끝 구분 기호를 사용해야 한다는 것을 깨달았습니다.제 질문은, 이들 중 하나가 프로토콜 버퍼에 있습니까?입니다.아직 사용하지 않았지만 문서를 살펴보면 길이 헤더나 구분 기호가 없는 것 같습니다.

그렇지 않다면 어떻게 해야 합니까?메시지를 작성한 다음 길이 헤더/EOP 구분 기호로 접두사/접미사를 붙여야 합니까?

도움이 되었습니까?

해결책

프로토콜에 크기나 끝 표시를 포함해야 합니다.스트림 기반 소켓(TCP/IP)에는 임의적으로 별도의 패킷으로 분할된 무기한 옥텟 스트림을 지원하는 것 외에는 아무것도 내장되어 있지 않습니다(그리고 패킷도 전송 중에 유출될 수 있습니다).

간단한 접근 방식은 각 "메시지"에 고정 크기 헤더를 갖고 프로토콜 버전과 페이로드 크기 및 기타 고정 데이터를 모두 포함하는 것입니다.그런 다음 메시지 내용(페이로드)입니다.

선택적으로 메시지 바닥글(고정 크기)을 체크섬 또는 암호화 서명과 함께 추가할 수 있습니다(신뢰성/보안 요구 사항에 따라 다름).

페이로드 크기를 알면 메시지의 나머지 부분에 충분한 바이트 수를 계속 읽을 수 있습니다(더 적은 용량으로 읽기가 완료되면 전체 메시지가 수신될 때까지 나머지 바이트에 대해 또 다른 읽기를 수행합니다).

종료 메시지 표시기를 사용하는 것도 가능하지만 동일한 옥텟 시퀀스가 ​​포함된 메시지를 처리하는 방법을 정의해야 합니다.

다른 팁

파티에 늦게 도착한 것에 대해 사과합니다. 저는 C# 구현 중 하나 인 Protobuf-Net의 저자입니다. 네트워크 사용을 위해서는 [de] serializewithlengthprefix"메소드를 고려해야합니다. 그러면 자동으로 길이를 처리합니다. 소스에는 예가 있습니다.

나는 오래된 게시물에 대해 크게 자세히 설명하지 않지만 더 알고 싶다면 의견을 추가하면 다시 연락을 드리겠습니다.

나는 헤더가 프로토콜 버퍼의 바닥글보다 낫다는 Matt의 의견에 동의합니다. 주된 이유는 PB가 바이너리 프로토콜이기 때문에 유효한 메시지 시퀀스가 ​​아닌 바닥글을 만드는 것이 문제가 되기 때문입니다.메시지 내용이 정의된 범위(일반적으로 0x20 - 0x7F ASCII)에 있기 때문에 많은 바닥글 기반 프로토콜(일반적으로 EOL 프로토콜)이 작동합니다.

유용한 접근 방식은 가장 낮은 수준의 코드가 소켓에서 버퍼를 읽고 이를 전체 메시지를 조합하고 부분 메시지를 기억하는 프레이밍 계층에 표시하도록 하는 것입니다(저는 이에 대한 비동기 접근 방식을 제시합니다(CCR 사용). 여기, 라인 프로토콜의 경우에도 불구하고).

일관성을 위해 항상 메시지를 세 가지 필드가 있는 PB 메시지로 정의할 수 있습니다.길이는 고정 정수, 유형은 열거형, 실제 데이터를 포함하는 바이트 시퀀스입니다.이렇게 하면 전체 네트워크 프로토콜이 투명하게 유지됩니다.

UDP뿐만 아니라 TCP/IP에는 크기에 대한 언급이 포함되어 있습니다. 그만큼 IP 헤더 IP 헤더의 길이를 지정하는 16 비트 필드가 포함되어 있습니다. 그리고 바이트의 데이터. 그만큼 TCP 헤더 32 비트 단어로 TCP 헤더의 크기를 지정하는 4 비트 필드가 포함되어 있습니다. 그만큼 UDP 헤더 UDP 헤더의 길이를 지정하는 16 비트 필드가 포함되어 있습니다. 그리고 바이트의 데이터.

여기에 있습니다.

C#의 System.net.sockets 네임 스페이스를 사용하든 Win32의 기본 Winsock 물건을 사용하든 Windows에서 표준 실행 소켓을 사용하면 IP/TCP/UDP 헤더를 볼 수 없습니다. 이 헤더는 소켓을 읽을 때 얻는 것이 실제 페이로드, 즉 전송 된 데이터가되도록 제거됩니다.

소켓을 사용하여 내가 본 모든 것의 일반적인 패턴은 보내려고하려는 데이터보다 먼저 응용 프로그램 수준 헤더를 정의한다는 것입니다. 최소한이 헤더에는 따라야 할 데이터의 크기가 포함되어야합니다. 이를 통해 크기에 대해 추측하지 않고도 각 "메시지"를 전체적으로 읽을 수 있습니다. 예를 들어, 패턴, CRC, 버전, 메시지 유형 등을 원하는만큼 멋진 일을 할 수 있지만 "메시지"의 크기는 전부입니다. 진짜 필요.

그리고 그 가치가있는 것에 대해, 나는 패키지 종단 구분 기호 대신 헤더를 사용하는 것이 좋습니다. EOP Delimiter에 중요한 단점이 있는지 확실하지 않지만 헤더는 내가 본 대부분의 IP 프로토콜에서 사용하는 접근법입니다. 또한, 내 스트림에 어떤 패턴이 나타나기를 기다리지 않고 내 메시지가 완료되었음을 나타내는 것이 아니라 처음부터 메시지를 처리하는 것이 더 직관적 인 것 같습니다.

편집 : Google 프로토콜 버퍼 프로젝트 만 알게되었습니다. 내가 말할 수있는 바에 따르면, 그것은 WCF를위한 이진 직렬화/디-시리얼 화 방식입니다 (나는 그것이 심한 과도한 단순화라고 확신합니다). WCF를 사용하는 경우 WCF 배관이 장면 뒤에서이 문제를 해결하기 때문에 전송되는 메시지의 크기에 대해 걱정할 필요가 없습니다. 아마도 프로토콜에서 메시지 길이와 관련된 것을 찾지 못했을 것입니다. 버퍼 문서. 그러나 소켓의 경우 크기를 아는 것은 위에서 논의한 바와 같이 엄청나게 도움이 될 것입니다. 내 생각에 프로토콜 버퍼를 사용하여 데이터를 직렬화 한 다음 보내기 전에 제기 한 응용 프로그램 헤더를 처리 할 것입니다. 수신 측면에서 헤더를 꺼낸 다음 나머지 메시지를 해제 할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top