2011-03-12 10 views
2

클라이언트 - 서버 프로그램이 있습니다.TcpClient에서 데이터를 올바르게 수신하지 못했습니다.

나는이 같은 데이터를 전송하고 있습니다 :

private void Sender(string s,TcpClient sock) 
{ 
    try 
    { 
     byte[] buffer = Encoding.UTF8.GetBytes(s); 
     sock.Client.Send(buffer); 
    }catch{} 
} 

및 클라이언트 측에서

은 다음과 같이 수신 :

byte[] buffer = new byte[PacketSize]; 
int size = client.Client.Receive(buffer); 
String request = Encoding.UTF8.GetString(buffer, 0, size); 

문제는 데이터가 완벽하게 때로는 유일한 부분입니다, 항상 수신되지이다 내가 보낸 것의 PacketSize은 내가 보내는 바이트보다 많은 10240입니다. 나는 또한 양쪽에 SendBufferSize와 ReceiveBufferSize를 설정했다.

최악의 경우 데이터가 완전히 수신되는 것입니다.

무슨 문제 일 수 있습니까?

답변

7

TcpClient.Receive에 의해 반환되는 값은 보낸 버퍼링 된 문자열의 길이와 같지 않습니다. 이는 Send 전화와 함께 보낸 모든 데이터를 한 번 반환하면 Receive으로 전화 할 때 보장 할 수 없기 때문입니다. 이 동작은 TCP가 작동하는 방식에 고유합니다 (메시지 기반 데이터 프로토콜이 아닌 스트림입니다).

제공된 버퍼는 한도 인 의 Receive가 반환 할 수 있기 때문에 더 큰 버퍼를 사용하여 문제를 해결할 수 없습니다. 1MB 버퍼를 제공하고 읽을 데이터가 1MB 인 경우에도 Receive은 합법적으로 모든 바이트 수를 반환 할 수 있습니다 (단 1 개만 허용).

Encoding.GetString을 호출하기 전에 모든 데이터를 버퍼링했는지 확인해야합니다. 그렇게하려면 먼저 얼마나 많은 데이터가 있는지 알아야합니다. 보낼 때 그래서 적어도, 당신은 문자열 바이트의 길이를 작성해야합니다 : 수신 할 때, 먼저 (알려진 고정 된 크기를 가지고있는 4 바이트)의 길이를 읽

byte[] buffer = Encoding.UTF8.GetBytes(s); 
    byte[] length = BitConverter.GetBytes(buffer.Length); 
    sock.Client.Send(length); 
    sock.Client.Send(buffer); 

다음 시작 버퍼링 나머지 데이터는 length 바이트가 될 때까지 임시 버퍼에 저장됩니다 (이 경우 Receive 호출이 임의로 걸릴 수 있으므로 while 루프가 필요함). 그래야만 Encoding.GetString으로 전화하여 원래의 문자열을 되 찾을 수 있습니다. 행동의

설명 당신은 관찰 :

OS의 네트워크 스택은 거의 보장, 연습는 일반적으로 데이터 당신에게 하나 개의 TCP 패킷을 줄 것이다에 Receive 호출을 제공하지 않는다하더라도 . TCP의 MTU (최대 패킷 크기)가 페이로드에 약 1500 바이트를 허용하기 때문에 문자열이이 크기보다 작 으면 순진한 코드가 올바르게 작동합니다. 그 이상이되면 여러 개의 패킷으로 분할되고 하나의 Receive은 데이터의 일부만 리턴합니다.

+1

+1. TCP 클라이언트/스트림에서 시간 초과를 사용하는 것을 잊어 버리십시오. 그렇지 않으면 데이터를 전송하는 응용 프로그램이 네트워크 문제를 가지고 있거나 응용 프로그램에 네트워크 문제가있는 경우 응용 프로그램이 중단됩니다. – stefan

+0

@stefan : 대신에 Async 메소드를 사용하는 것이 더 낫다. 하지만 기본 원리를 먼저 익히자. – Jon

+0

@Jon Async yes를 사용하는 것이 더 나을 수 있지만 실제로는 응용 프로그램에 달려있다. – stefan

관련 문제