2014-07-25 80 views
1

我有一個關於如何使用IO :: Socket的問題;我有一個應該不斷運行的腳本,監視某個事件的Asterisk服務器。當這些事件發生時,腳本通過TCP套接字將事件中的數據發送到另一臺服務器。偶爾我發現,socket會關閉。我的問題是我是否應該使用一個套接字,並永遠保持打開狀態(並弄清楚爲什麼+阻止它關閉),還是應該爲發送的每一位數據打開並關閉一個新套接字?
我對這類事情的經歷非常少,我讀過所有的文檔,但沒有找到我正在尋找的答案。下面是我到目前爲止已經有了一個樣本:在perl中正確使用IO :: Socket :: INET用於TCP客戶端

#!/usr/bin/perl 
use Asterisk::AMI; 
use IO::Socket; 
use strict; 
use warnings; 

my $sock = new IO::Socket::INET (
    PeerAddr => '127.0.0.1', 
    PeerPort => '1234', 
    Proto => 'tcp', 
); 

sub newchannel { 
    my ($ami, $event) = @_; 

    if ($event->{'Context'} eq "from-trunk") { 

    my $unique_id = $event->{'Uniqueid'}; 
    my $this_call = $call{$unique_id}; 

    $this_call->{caller_name} = $event->{'CallerIDName'}; 
    $this_call->{caller_number} = $event->{'CallerIDNum'}; 
    $this_call->{dnis} = $event->{'Exten'}; 

    $call{$unique_id} = $this_call; 
    }; 

} 

sub ringcheck { 
    my ($ami, $event) = @_; 

    if ($event->{SubEvent} eq 'Begin') { 
    my $unique_id = $event->{UniqueID}; 
    if (exists $call{$unique_id}) { 

     my $this_call = $call{$unique_id}; 

     $this_call->{system_extension} = $event->{Dialstring}; 
     $this_call->{dest_uniqueid} = $event->{DestUniqueID}; 


     printf $sock "R|%s|%s|%s||%s\n", 
     $this_call->{caller_name}, 
     $this_call->{caller_number}, 
     $this_call->{system_extension}, 
     $this_call->{dnis}; 

     $this_call->{status} = "ringing"; 
    } 
} 

還有比這更給它一點,但是這顯示了,我覺得我應該開始/停止新的套接字(在ringcheck子內) 。

讓我知道如果你需要我澄清或添加任何東西。

謝謝!

回答

1

無論是更好地建立每個消息一個新的連接或保持連接打開取決於幾個因素:

  • 是與建立連接顯著相關的開銷?這取決於諸如消息需要發送的頻率以及網絡連接的質量等因素。

    如果遠程端是'localhost',就像上面的示例腳本一樣,那麼這可能不是問題,事實上在這種情況下,我會推薦使用Unix域套接字。

  • 遠端是否發回任何東西?如果任何一方可能有異步消息發送,則更難管理零星連接。聽起來不像你這樣的情況。

  • 是否有任何重要的資源,你會通過保持連接打開而保持?

請注意,我不認爲隨機連接丟失是爭論每次創建新連接的好理由。如果可能,最好在任何情況下診斷該問題。否則,無論您採取什麼方法,您都可能獲得不可靠的表現。

根據我的經驗,在長期持有的TCP連接中看似隨機丟失的一個常見原因是中間跟蹤防火牆。如果這些防火牆在一段時間內沒有看到任何活動,就會丟棄一個連接來保存自己的資源。要解決這個問題,我在我的一些工具使用的一種方法,就是設置套接字選項SO_KEEPALIVE套接字上,像這樣:

use Socket; 
... 
setsockopt($sock, SOL_SOCKET, SO_KEEPALIVE, 1); 

這有幾個好處 - 它導致內核輪詢時間即使所有設備都安靜,它本身也足以讓部分防火牆保持開心,但是您的連接仍會定期收到消息。另外,如果你的連接斷開,你的程序可以直接找到,而不是下一次你想寫入它(儘管你不會注意到它,除非你經常檢查你的套接字錯誤)。

也許你最好的辦法可能是設置SO_KEEPALIVE,並保持你的套接字打開,但也要檢查錯誤,每當你試圖寫入它,並且如果你有錯誤,關閉並重新打開連接。

This question也可能對您有用。

+0

開銷並不重要。這全是局域網,並且可能每10分鐘少於一條消息。遠端沒有發回任何東西。沒有什麼重要的事情可以用來做這些事情;我沒有看到沒有打開連接的理由。我的部分問題是,我無法訪問此連接的另一端,因此必須使用我所擁有的功能來排除故障。你的回答非常有幫助,我會嘗試Keepalive選項,並在今天晚些時候再回來查看。再次感謝。 – lorsungcu

+0

似乎已經工作了,從那以後沒有下降過。謝謝你的偉大答案。 – lorsungcu