2011-10-16 3 views
1

수신 측이 Go 인 소켓을 통해 잘 통신하는 두 개의 작은 프로그램이 있습니다. 내 메시지가 1024 바이트 버퍼에 들어가기에 충분히 작고 연결에서 하나의 읽기에서 수신 할 수 있지만 지금은 100k + 이상의 이미지에서 데이터를 전송하려고 할 때 모든 것이 복숭아로 작동합니다. 모든 이미지가 내부에 들어갈 때까지 버퍼를 늘리지 않는 것이 올바른 해결책이라고 가정합니다.Go에서 소켓을 통해 파일 데이터를 검색하려면 어떻게합니까?

의사 이동 : 나는 내 소켓 루틴을 읽을 개선 할 수있는 방법을

var buf = make([]byte,1024) 
conn, err := net.Dial("tcp", ":1234") 

for { 
    r, err := conn.Read(buf[0:]) 
    go readHandler(string(buf[0:r]),conn) 
} 

는 몇 바이트의 간단한 메시지도 큰 데이터를 모두 받아? 전체 이미지 데이터를 image.Decode에서 사용하기 위해 io.Reader로 변환 할 수 있다면 보너스 포인트입니다.

답변

2

io.ReadFull을 사용하면 특정 길이의 []byte을 읽을 수 있습니다. 이것은 미리 읽어야 할 바이트 수를 미리 알고 있다고 가정합니다.

image.Decode의 경우 conn을 직접 image.Decode 함수에 전달할 수 있어야합니다. 이 경우 이미지가 디코딩 될 때까지 연결에서 읽기를 수행하지 않는다고 가정합니다.

귀하의 코드

for { 
    r, err := conn.Read(buf[0:]) 
    go readHandler(string(buf[0:r]),conn) 
} 

당신이 동시이 읽 다수를 가진 끝날 것 때문에 conn에서 읽고 시작하는 goroutine 이것은 좋은 생각은 아닌 것 같아 것을 제안 할 것으로 보인다 (읽기가 일어나는 순서를 제어하지 않고) : 하나는 for 루프에, 다른 하나는 readHandler에있다.

+0

어떻게 conn에서 ReadFull을 할 수 있습니까? conn.i.Reader입니까? – Nick

+1

예. net.Conn에 "Read (b [] byte) (n int, err os.Error)"메서드가 있기 때문에 net.Conn은 io.Reader를 구현합니다. –

3

나는 Go의 TCP에 대한 직접적인 경험이 없지만 나에게 TCP가 제공하는 것의 아주 전형적인 오해의 희생이 된 것으로 보인다.

UDP와 SCTP과는 달리, TCP는 스트림 지향이기 때문에 메시지 경계 개념이 없습니다. 즉, TCP는 불투명 한 바이트 스트림을 전송하며 수신 측과 관련하여 스트림을 "청킹"하는 것은 거의 제어 할 수 없다는 것을 의미합니다.

"100k + 메시지 보내기"는 보낸 사람 측의 런타임/네트워크 라이브러리에서 "메시지"를 내부 버퍼로 소비 한 다음 "OS"의 TCP를 스트리밍하여 "속이는"것으로 의심됩니다. 스택은 그것을 가능하게합니다 (유비쿼터스 하드웨어/소프트웨어에서 보통 약 8k입니다). 수신자가 스트림을 얻는 조각의 크기는 완전히 정의되지 않습니다. 정의 된 유일한 것은 스트림에있는 바이트의 순서이며 보존됩니다.

따라서 데이터 수신에 대한 귀하의 접근 방식을 다시 고려해야 할 수도 있습니다. 정확한 접근 방식은 데이터의 특성에 따라서 스트리밍되는 달라집니다

  • 가장 쉬운 방법 (응용 프로그램 수준의 프로토콜을 통해 컨트롤이있는 경우)되는에 다음 "메시지 페이로드"의 길이를 전달하는 고정 길이의 특수 길이 필드. 그런 다음 전체 메시지를 destreaming 두 단계 과정입니다 : 1) 길이 필드를 얻기 위해 그 많은 바이트를 받고, 그것을 읽고, 온전함에 대한 가치를 확인한 다음 2) 그 다음에 많은 바이트를 읽고 그것을 수행하십시오.
  • 앱 수준 프로토콜을 제어 할 수없는 경우 메시지 구문 분석이 더 복잡해지고 일종의 복잡한 상태 시스템이 필요합니다.

자세한 내용은 thisthis을 참조하십시오.

+0

나는 유사한 정보를 얻을 수 있기를 기대합니다! – Nick

관련 문제