2012-06-28 4 views
2

두 개의 프로세스 (또는 두 개의 스레드) 사이에서 하나의 소켓을 공유하고 두 개의 소켓 모두 큰 메시지 (밑줄 친 프로토콜 버퍼보다 ​​큼)를 보내려고하면 그 것이 보장됩니다. 두 메시지가 순차적으로 전송됩니까? 또는 메시지가 커널 내부에서 인터리브 될 수 있습니까?소켓이 동시성 보증을 보냅니다.

주로 TCP over IP 동작에 관심이 있지만 소켓 프로토콜에 따라 달라지는 지 알아 보는 것은 흥미로울 것입니다.

답변

4

메시지 write() 메시지 A, 다음 B가 동일한 소켓에 있으면 B보다 먼저 도착할 것을 보장합니까? SOCK_STREAM (예 : TCP) 및 SOCK_SEQPACKET (거의 사용되지 않음) 소켓의 경우 대답은 정규화되지 않은 예입니다. 인터넷 (즉, UDP 패킷)을 통한 SOCK_DGRAM의 경우, 응답은 아니오입니다. 패킷은 네트워크에 의해 재정렬 될 수 있습니다. 단일 호스트에서 유닉스 도메인 데이터 그램 소켓은 (내가 아는 모든 시스템에서) 순서를 유지하지만, 모든 표준에 의해 보장된다는 것은 믿을 수 없으며 가장자리 경우가 있다고 확신한다.

또는 기다려주세요. 두 프로세스에서 작성한 메시지가 섞이지 않을지 궁금한가요? 예 : 단일 시스템 호출 (write/writev/sendto/sendmsg)은 항상 내용을 파일 설명자에 원자 적으로 배치합니다. 하지만 분명히 당신이나 당신의 도서관이 여러 번 전화를 걸면 그 보장을 잃게됩니다.

1

UDP의 경우 두 스레드가 동시에 소켓 핸들에 쓰면 두 메시지가 별도의 데이터 그램으로 보내집니다. 패킷이 MTU보다 큰 경우 IP 단편화가 발생하지만 결과 데이터 그램은 수신기에서 올바르게 보존 및 재구성됩니다. 즉 UDP (데이터 그램 재주문, 패킷 손실 등)와 관련된 일반적인 문제를 제외하고는 UDP에 안전합니다.

스트림 기반 TCP의 경우 잘 모르겠습니다. 당신의 질문은 본질적으로 "두 개의 쓰레드가 같은 파일 핸들에 쓰려고한다면 그 파일은 여전히 ​​읽을 수있을 것입니까?" 나는 실제로 그 해답을 모른다.

가장 간단한 방법은 스레드 안전 잠금 (mutex)을 사용하여 소켓에 대한 보내기/쓰기 호출을 보호하여 스레드에서만 한 번에 소켓에 ​​쓸 수 있도록하는 것입니다.

TCP의 경우 모든 소켓 IO를 처리하기위한 전용 스레드가 있어야합니다. 그런 다음 작업자가 보낸 메시지가 소켓 스레드에 비동기 적으로 대기하여 보낼 수있는 방법을 고안하십시오. 소켓 스레드는 recv() 호출을 처리하고 소켓 연결이 원격 측에 의해 종료 될 때 다른 스레드에 알릴 수 있습니다.

+0

나는 2 개의 다른 프로세스에서 소켓에 쓰고있어, 내 문제가있어 : 프로세스간에 메시지를 전달하지 마십시오 프로세스), 소켓을 통해 전송하는 것이 훨씬 더 바람직합니다. 필자는 세마포어와 쓰기를 동기화 할 수 있지만, 커널이 어쨌든 그렇게한다면 번거 로움을 피하는 것을 선호한다. – lvella

+0

UDP를 통한 sendto()가 threadsafe인지 알아 내려고하면서이 대답을 보았습니다. 그렇다면 그렇습니까? 그렇다면 위대합니다! – fluffy

0

기본 버퍼 크기를 초과하는 큰 크기의 메시지를 STREAM 소켓으로 보내려고하면 짧은 쓰기가 보장됩니다. 쓰기 또는 보내기 호출은 데이터의 일부만 작성합니다 (버퍼에 저장할 수있는만큼) 남은 데이터에 대해 다른 쓰기를 수행하도록 작성된 양을 리턴합니다.

여러 스레드 또는 프로세스에서이 작업을 수행하면 각 쓰기 (또는 보내기)가 메시지의 작은 부분을 송신 버퍼에 원자 적으로 기록하지만 후속 쓰기는 순서에 관계없이 발생할 수 있습니다. 전송되고있는 큰 버퍼는 인터리브됩니다.

DGRAM 소켓에서 메시지를 보내는 경우 전체 메시지가 원자 적으로 (단일 계층 4 패킷으로, 프로토콜 스택의 하위 계층에서 조각화되고 다시 어셈블 됨) 또는 오류 (EMSGSIZE 리눅스 또는 다른 유닉스 변형)

+0

MSG_WAITALL 플래그를 사용하여 큰 메시지를 작성하면 어떻게됩니까? 이것은 원자적일 것인가? – FaceBro

+0

'MSG_WAITALL'은 쓰기에만 지원되지 않습니다. –

+1

아니요, 읽기 및 쓰기 모두에 사용할 수 있습니다. – FaceBro