2010-03-27 2 views
3

TCP 서버 (즉, netcat)에 연결하는 루비 코드가 있습니다. 그것은 20 회 반복되며 "ABCD"를 보냅니다. netcat을 죽이면 예외가 발생하기 위해 루프를 두 번 반복합니다. netcat이 죽은 후 첫 번째 루프에서 아무 예외도 발생하지 않고 "send"는 5 바이트가 올바르게 기록되었다고보고합니다. 물론 결국 서버가 절대로 수신하지 못했기 때문에 어느 쪽이 맞지 않습니다.Ruby TCPSocket은 서버가 종료되었을 때 알리지 않습니다.

이 문제를 해결할 방법이 있습니까? 지금은 데이터를 잃어 버리고 있습니다. 올바르게 전달되었다고 생각하기 때문에 다시 재생하지 않을 것입니다.

#!/usr/bin/env ruby 
require 'rubygems' 
require 'socket' 

sock = TCPSocket.new('192.168.0.10', 5443) 
sock.sync = true 

20.times do 
    sleep 2 
    begin 
    count = sock.write("ABCD ") 
    puts "Wrote #{count} bytes" 
    rescue Exception => myException 
    puts "Exception rescued : #{myException}" 
    end 
end 

답변

1
나는 sleep 기능이없는 시도

여전히 운 (그냥 아무것도 개최에 넣어되지 않은 확인하지 않으려면)과 :

#!/usr/bin/env ruby 
require 'rubygems' 
require 'socket' 
require 'activesupport' # Fixnum.seconds 

sock = TCPSocket.new('127.0.0.1', 5443) 
sock.sync = true 

will_restart_at = Time.now + 2.seconds 
should_continue = true 

while should_continue 
    if will_restart_at <= Time.now 
    will_restart_at = Time.now + 2.seconds 
    begin 
     count = sock.write("ABCD ") 
     puts "Wrote #{count} bytes" 
    rescue Exception => myException 
     puts "Exception rescued : #{myException}" 
     should_continue = false 
    end 
    end 
end 

나는 Wireshark를 분석하고 두 솔루션은 정확하게 행동하고 있습니다 동일하게.

실제로는 your_socket.write (가능한 파괴를 조사하지 않았기 때문에 소켓이 열렸으므로 실패하지 않음)까지 소켓을 불러 오지 않을 것이라고 생각합니다. 오류.

나는 이것을 nginx와 수동 TCP 소켓으로 시뮬레이션하려고 시도했다. 그리고 그것을보십시오 :

irb> sock = TCPSocket.new('127.0.0.1', 80) 
=> #<TCPSocket:0xb743b824> 
irb> sock.write("salut") 
=> 5 
irb> sock.read 
=> "<html>\r\n<head><title>400 Bad Request</title></head>\r\n<body>\r\n</body>\r\n</html>\r\n" 

# Here, I kill nginx 

irb> sock.write("salut") 
=> 5 
irb> sock.read 
=> "" 
irb> sock.write("salut") 
Errno::EPIPE: Broken pipe 

그럼 결론은 뭔가요? 실제로 서버의 일부 데이터가 필요하지 않다면 연결이 끊어 졌음을 감지하여 망쳐 버린 것입니다.

+0

이 소켓에서 읽는 IO.select가 true를 반환합니다. 그래서 적어도 당신이 그것을 사용한다면, 당신은 읽을 줄 알게 될 것입니다. 그리고 그것은 오류를 던질 것입니다. 조용히 실패하는 것보다 훨씬 낫습니다. 이 답변을 게시 해 주셔서 감사합니다. 그것은 다른 사람들이이 이상한 행동을 보는 것을 나에게 더 기분 좋게 만듭니다. 참고 : jruby와 mri 1.9.3에서이 내용을 볼 수 있습니다. – kbrock

1

정상적으로 감지하려면 소켓에서 읽어야합니다. 소켓이 닫혔다는 것을 나타냅니다.

데이터가 성공적으로 전송되었는지 알아야 할 경우 애플리케이션 수준에서 데이터의 ACK를 구현하는 것 외에는 방법이 없습니다.

+0

사실. 그래서 내가 망했다는 것을 의미합니까? "바이너리 인터페이스는 바이너리 컨텐트에 일반 TCP 소켓을 사용하며 본질적으로 스트리밍이며 응답 응답이 없습니다." http://developer.apple.com/iphone/library/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingWithAPS /CommunicatingWIthAPS.html#//apple_ref/doc/uid/TP40008194-CH101-SW3 – Ecco

2

데이터를 전송할 때 데이터가 TCP 출력 버퍼에 기록 될 때 차단 호출이 반환됩니다. 버퍼가 가득 차면 서버가 이전에 전송 된 데이터의 수신을 확인하기를 기다리는 동안에 만 차단됩니다.

이 데이터가 버퍼에 있으면 네트워크 드라이버가 데이터를 보내려고합니다. 두 번째 연결 시도에서 연결이 끊어지면 응용 프로그램은 끊어진 연결 상태를 발견합니다.

또한 연결은 어떻게 닫습니까? 서버가 연결을 적극적으로 닫고 있습니까? 이 경우 클라이언트 소켓은 다음 소켓 호출시 알림을받습니다. 아니면 추락 했나요? 아니면 더 이상 통신 할 수 없음을 의미하는 네트워크 오류가있을 수 있습니다.

끊어진 연결 발견은 소켓을 통해 데이터를 보내거나받을 때만 발생합니다. 이는 연결을 적극적으로 닫는 것과는 다릅니다. 연결을 사용하지 않고 연결이 아직 살아 있는지 확인할 수 없습니다.

쓰기 후에 sock.recv(0)을 시도하십시오. 소켓에 오류가 발생하면 "Errno::ECONNRESET: Connection reset by peer - recvfrom(2)"이 발생합니다. sock.sendmsg "", 0 (sock.write 또는 sock.send가 아닌)을 시도해 볼 수도 있습니다.이 경우 "Errno::EPIPE: Broken pipe - sendmsg(2)"이 표시됩니다.

TCP 패킷을 손에 들고 다른 쪽에서 데이터가 수신되었다는 확인을받는 경우에도 서버가이 데이터를 처리했다는 보장은 없습니다. 입력 버퍼에 있지만 아직 없습니다. 처리됨.

이 모든 이전 깨진 연결을 식별하는 데 도움이 수 있지만 여전히 데이터가 을 받고 서버에서 처리 된 것을 보장하지 않습니다. 응용 프로그램이 메시지를 처리했는지 확인하는 유일한 방법은 응용 프로그램 수준의 응답입니다.

+0

나중에 참조 할 수 있습니다 - 메소드의 이름에 오타가 있습니다 (send_msg가 아닌'sendmsg'입니다). 확실한 치명적인 증거가 될 것 같은 노골적인 사본 - 주인을 위해. 편집 할 때 6 자 제한이 아니라면 직접 수정해야합니다. – Tomalla

관련 문제