2010-06-20 3 views
0

원격 종단점을 범람시키지 않으려면 내 서버 앱이 전송하려는 패킷의 "송부 (to-send)"대기열을 구현해야합니다.TCP로 양호한 "송부"대기열 구현

Windows Winsock, I/O 완료 포트를 사용합니다.

내 코드가 "socket-> send (.....)"를 호출 할 때 내 맞춤 "send()"함수가 데이터가 이미 "유선"에 있는지 확인합니다. 그 소켓).
실제로 데이터가 유선에있는 경우 나중에 전송할 데이터를 대기열에 넣습니다.
데이터가 연결되어 있지 않으면 WSASend()를 호출하여 실제로 데이터를 보냅니다.

지금까지 모든 것이 좋습니다.

이제는 보낼 데이터의 크기가 예측할 수 없으므로 작은 패킷의 메모리를 낭비하지 않기 위해 작은 덩어리 (예 : 64 바이트)로 나누고이 작은 덩어리를 보냅니다. .

내가 보낸 패킷에 대해 "write-done"완료 상태가 IOCP에 의해 주어지면 나는 다음 패킷을 큐에 보냅니다.

그게 문제입니다. 속도가 너무 느립니다. 사실 저는 실제로 로컬 연결 (127.0.0.1) 속도가 200kb/s입니다.

따라서 WSAnd()를 seveal 청크 (WSABUF 객체 배열)와 호출해야한다는 것을 알았습니다. 그러면 성능이 훨씬 향상되지만 한 번에 얼마나 많이 보내겠습니까?
바이트의 권장 크기는 있습니까? 그 대답은 내 요구에 맞을 것이라고 확신하지만 아직 시작해야 할 "일반적인"요점이 있음을 확신합니다.
더 좋은 방법이 있습니까?

답변

1

물론 피어가 처리 할 수있는 것보다 빠르게 데이터를 보내려는 경우 (링크 속도 또는 피어가 데이터를 읽고 처리 할 수있는 속도로 인해) 큐를 제공하는 것만으로도 충분합니다. 그런 다음 사용중인 시스템 자원의 양을 제어하려는 경우에만 자체 데이터 대기열을 사용해야합니다. 당신이 단지 몇 개의 연결 만 가지고 있다면 그것은 이것이 모두 불필요 할 것입니다. 당신이 1000을 가지고 있다면 그것은 당신이 염려 할 필요가있는 것입니다. 여기에서 알아야 할 중요한 점은 비동기 네트워크 중 하나를 사용하여 Windows에서 관리되는 API 또는 관리되지 않는 API를 사용하는 경우 보내는 버퍼의 수명주기 동안 수신 응용 프로그램과 네트워크로 제어 권한을 넘겨주는 것입니다. 자세한 내용은 here을 참조하십시오.

그리고이 문제를 해결해야한다고 결정한 후에는 피어가 데이터를 빠르게 처리 할 수 ​​있다면 항상 신경 쓰지 않아도됩니다. 큐를 생성하여 속도를 늦출 필요가 없습니다. 보낸 사람에게. TCP 스택이 흐름 제어 문제 (http://www.tcpipguide.com/free/t_TCPWindowSizeAdjustmentandFlowControl.htm 참조)로 인해 더 이상 데이터를 전송할 수 없기 때문에 사용자가 작성한 중복 된 쓰기가 완료 될 수 없기 때문에 쓰기 완료 시간이 오래 걸리기 때문에 데이터를 대기열에 두어야합니다. 이 시점에서 잠재적으로 제한되지 않은 양의 제한된 시스템 리소스를 사용할 수 있습니다. 비 페이징 풀 메모리와 잠길 수있는 메모리 페이지 수는 제한되어 있습니다 (알고있는 한 알 수있는 한). 둘 다 보류중인 소켓 쓰기에 사용됩니다. ..

어쨌든, 그 중 ... 이미 전송 대기열을 추가하기 전에 좋은 처리량을 달성했다고 가정합니다. 최대의 성능을 얻으려면 TCP 창 크기를 기본값보다 큰 값으로 설정하고 (http://msdn.microsoft.com/en-us/library/ms819736.aspx 참조) 연결에 중복 된 겹쳐 쓰기를 게시해야합니다.

대기열을 시작하기 전에 대기중인 겹쳐진 쓰기를 허용해야하는 경우 이미 처리량이 충분하다고 가정하면 전송 준비가 완료된 데이터의 양이 최대화됩니다. 보류중인 쓴 편지의 매직 번호를 확인한 후에는 데이터를 대기열에 넣은 다음 후속 완료에 따라 보낼 수 있습니다. 물론 모든 데이터가 대기 상태가되면 모든 추가 데이터가 대기열에 있어야합니다. 속도와 사용 된 리소스 (즉, 유지할 수있는 동시 연결 수) 간의 균형을 유지하는 데 가장 적합한 것이 무엇인지 확인하려면 구성 가능한 번호와 프로필을 만드십시오.

IOCP를 사용하기 때문에 데이터 버퍼 대기열에 단일 항목으로 전송 될 예정인 전체 데이터 버퍼를 대기열에 놓아 두는 경향이 있습니다. 이러한 데이터 버퍼가 이미 참조 카운트되어 있으므로 쉽게 참조 할 수 있습니다. 큐에있는 데이터가있는 동안 보내기 버퍼에 대한 참조를 보유하기 만하면 큐잉 프로세스가 간단 해지고 보내기를 한 번 풀어 놓으면 큐잉 프로세스가 더 간단 해집니다.

개인적으로 기본 작업을 수행 할 때까지 여러 WSABUF와 함께 스 캐터/수집 쓰기를 사용하여 최적화하지 않을 것입니다. 그렇게하면 성능이 실제로 향상된다는 것을 알 수 있습니다. 이미 보류중인 데이터가 충분한 지 의심 스럽습니다. 항상 그렇듯이 측정하고 알게 될 것입니다.

64 바이트가 너무 작습니다.

당신은 이미 이것을 보았을 것입니다.하지만 여기에 주제에 대해 썼습니다 : http://www.lenholgate.com/blog/2008/03/bug-in-timer-queue-code.html 아마도 당신에게 너무 모호합니다.

+0

Len에게 많은 감사를드립니다. 이제이 물건을 구현 한 후에, 나는 정말로 당신의 말을 이해할 수 있습니다. 문제가 해결되었습니다. 그것은 생각보다 간단했습니다. 지금은 버퍼 관리, 소켓에 게시, 그리고 필요에 따라 제한하는 것이 전부입니다. – Poni