Tommy 碎碎念

Tommy Wu's blog

« 上一篇 | 下一篇 »

終於解決了 ADSL 斷線的問題!
post by tommy @ 21 四月, 2006 22:55
我家 12M/1M 的 Hinet ADSL, 在最近, 發現連線速度十分不正常, 而且上星期開始, 一天斷線的次數可能有數十次, 雖然每次斷線都在幾秒內可以重新建立連線, 但是對於使用上, 總是不怎麼方便.

其實這個問題, 在這半年來似乎每隔一個多月就會發生一次, 多數會持續一個星期左右. 等我受不了時, 就會請我家人打電話給中華電信叫修. 可是由於出問題的時候, 都是我不在台灣的時候, 無法讓中華電信的人員進來我家維修, 所以都不了了之, 也很神奇的在電話叫修之後沒多久, 都會恢復正常.

不過, 這次有點不同, 由上星期開始, 持續有問題到這星期, 而我剛好這星期回來休假, 就順便再叫修了.

4/19 早上打電話後, 下午就有人來看了, 服務態度很好, 可是似乎看不出有什麼問題, 電話的接法與聲音都很正常, 看起來不像有問題的樣子. 而且... 人來的時候, 似乎 ADSL 線路也怕他, 居然整個下午都很正常. 所以就請我再觀察看看, 有問題再打電話叫修一次.

所以, 為了觀察這情形, 就寫了一個 script, 每分鐘抓一次數據, 看看有沒有變動, 用來產生這個網頁, 以便我觀察斷線情形. 結果... 當天晚上就發現斷線十幾次, 連線的下傳速度由 6M-10M 之間跳動, 且... 我需要的上傳速度由 500K-900K. 實在讓我無法接受. 所以 4/20 當天早上就打電話再叫修了.

下午, 同樣一位先生打了電話給我, 似乎在我家社區查線, 說可能會斷線一陣子. 隔了十幾分鐘, 就來到我家, 跟我說他找到原因了, 說有另外一線電話 "搭線" 到我的線路上頭. 他把那條線路跳開後, 應該可以解決我的問題. 果然, 在他來我這兒的時候, 我看我的連線速度又回到 10M/1M 的水準. 他跟我說, 我的線路很簡單, 附近沒有人使用 ADSL,  只有我在用, 連線的水準應該在 10M/1M 才算正常. 我也很滿意的簽名送他回去.

可是... 好景不長. 在他離開我家門的五分鐘不到, 我就發現斷線了. 而且這次比較嚴重, 要等幾乎一分鐘才會恢復連線, 更糟的是, 連線的速度變成 4M/300K 左右. 我試著把 ATU-R 關閉再連, 一直都很差, 最高只能到 8M/800K 左右, 且很快就斷線, 再連時又會降速下來.

所以, 趕緊打電話到 0800-080-128 叫修, 請他找剛剛那位先生回來看一下. 還好還沒走遠, 約 30 分鐘後, 人就回來了, 這次, 他把我的線路直接跳到另外一條線路上頭. 果然, 線路恢復到 10M/1M 的水準. 他這次特地在我這兒等了約 10 分鐘, 讓我試著傳一些資料看看, 由 Hinet 的 ADSL ftp 測試網站抓資料回來, 都一直很穩定. 這次終於放心的回去了.

由上頭的連線觀察網頁, 可以發現, 果然由 4/20 下午 4 點多後, 速度就一直維持在 10M/1M 左右, 十分穩定, 沒有任何斷線異動的記錄了. 中華電信總算把困擾我這一陣子的連線問題解決了. 希望不會再發生了.  


2006/06/27: 我是把資料存到 mysql 中, 所以你必須有一個 mysql 資料庫, 建立一個 table 如下:

CREATE TABLE `myadsl` (
`adsl_time` datetime NOT NULL,
`adsl_uplink` int(11) default NULL,
`adsl_downlink` int(11) default NULL,
PRIMARY KEY (`adsl_time`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

然後每分鐘執行下列的 script 一次:

#!/usr/bin/php -Cq
<?php

$dbhost = 'localhost';
$dbuser = 'your_db_username';
$dbpass = 'your_db_password';
$dbname = 'your_db_name';

$adsl_user = 'cht';
$adsl_pass = 'chtnadsl';
$adsl_host = '192.168.1.1';
$adsl_info = 'info.html';

$adsl_url = 'http://'.$adsl_user.':'.$adsl_pass.'@'.$adsl_host.'/'.$adsl_info;

list($upload, $download) = get_speed($adsl_url);

$conn = @mysql_connect($dbhost, $dbuser, $dbpass);
if (!$conn) {
echo "Can't connect to database!\n";
exit;
}
@mysql_select_db($dbname, $conn);
@mysql_query("SET NAMES 'utf8'", $conn);

$sql = "select adsl_uplink, adsl_downlink
from myadsl
where adsl_time < now()
order by adsl_time desc
limit 1";
$result = @mysql_query($sql, $conn);
if ($result == false) {
@mysql_close($conn);
echo "SQL error: $sql\n";
echo "mysql code: ".@mysql_errno($conn)."\n";
echo "mysql error: ".@mysql_error($conn)."\n";
exit;
}
$row = @mysql_fetch_row($result);
@mysql_free_result($result);

if ($upload == $row[0] && $download == $row[1]) {
@mysql_close($conn);
exit;
}

$sql = "insert into myadsl (
adsl_time,
adsl_uplink,
adsl_downlink
) values (
now(),
$upload,
$download
)";

if (!@mysql_query($sql, $conn)) {
echo "SQL error: $sql\n";
echo "mysql code: ".@mysql_errno($conn)."\n";
echo "mysql error: ".@mysql_error($conn)."\n";
}
@mysql_close($conn);

exit;

function get_speed($adsl_url)
{
$lines = @file($adsl_url);
if ($lines == false) return array(0,0);

$get_rate = 0;
$upload = 0;
$download = 0;

foreach ($lines as $num => $line) {
if ($get_rate == 1) {
$download = trim(preg_replace("(\r\n|\n|\r|<td>|</td>| )", "", $line));
$get_rate = 2;
continue;
}
if ($get_rate == 2) {
$upload = trim(preg_replace("(\r\n|\n|\r|<td>|</td>| )", "", $line));
$get_rate = 2;
break;
}
if (strstr($line, 'Rate (Kbps):')) {
$get_rate = 1;
continue;
}
}
if ($upload == ' ') $upload = 0;
if ($download == ' ') $download = 0;
return array($upload, $download);
}

?>

修改上頭的 $dbuser, $dbpass, $dbname 三個變數, 或者, 如果不用資料庫的話, 也可以自己寫到檔案存起來. 

如果你需要的是給 CACTI 用的 script, 我是使用下頭這個:

#!/usr/bin/php -Cq
<?php

$adsl_user = 'cht';
$adsl_pass = 'chtnadsl';
$adsl_host = '192.168.1.1';
$adsl_info = 'statsadsl.html';

$adsl_url = 'http://'.$adsl_user.':'.$adsl_pass.'@'.$adsl_host.'/'.$adsl_info;

list($u_snr, $d_snr,
$u_att, $d_att,
$u_power, $d_power,
$u_att_rate, $d_att_rate,
$u_rate, $d_rate) = get_speed($adsl_url);

echo "Data:0 uplink:$u_rate downlink:$d_rate upsnr:$u_snr downsnr:$d_snr upatt:$u_att downatt:$d_att upattrate:$u_att_rate downattrate:$d_att_rate uppwr:$u_power downpwr:$d_power\n";

exit;

function get_speed($adsl_url)
{
$lines = @file($adsl_url);
if ($lines == false) return array(0,0);

$get_snr = 0;
$get_att = 0;
$get_power = 0;
$get_att_rate = 0;
$get_rate = 0;
$u_snr = 0;
$d_snr = 0;
$u_att = 0;
$d_att = 0;
$u_power = 0;
$d_power = 0;
$u_att_rate = 0;
$d_att_rate = 0;
$u_rate = 0;
$d_rate = 0;

foreach ($lines as $num => $line) {
if ($get_snr == 1) {
$d_snr = trim(preg_replace("(\r\n|\n|\r|<td>|</td>| )", "", $line));
$get_snr = 2;
continue;
}
if ($get_snr == 2) {
$u_snr = trim(preg_replace("(\r\n|\n|\r|<td>|</td>| )", "", $line));
$get_snr = 0;
continue;
}
if ($get_att == 1) {
$d_att = trim(preg_replace("(\r\n|\n|\r|<td>|</td>| )", "", $line));
$get_att = 2;
continue;
}
if ($get_att == 2) {
$u_att = trim(preg_replace("(\r\n|\n|\r|<td>|</td>| )", "", $line));
$get_att = 0;
continue;
}
if ($get_power == 1) {
$d_power = trim(preg_replace("(\r\n|\n|\r|<td>|</td>| )", "", $line));
$get_power = 2;
continue;
}
if ($get_power == 2) {
$u_power = trim(preg_replace("(\r\n|\n|\r|<td>|</td>| )", "", $line));
$get_power = 0;
continue;
}
if ($get_att_rate == 1) {
$d_att_rate = trim(preg_replace("(\r\n|\n|\r|<td>|</td>| )", "", $line));
$get_att_rate = 2;
continue;
}
if ($get_att_rate == 2) {
$u_att_rate = trim(preg_replace("(\r\n|\n|\r|<td>|</td>| )", "", $line));
$get_att_rate = 0;
continue;
}
if ($get_rate == 1) {
$d_rate = trim(preg_replace("(\r\n|\n|\r|<td>|</td>| )", "", $line));
$get_rate = 2;
continue;
}
if ($get_rate == 2) {
$u_rate = trim(preg_replace("(\r\n|\n|\r|<td>|</td>| )", "", $line));
$get_rate = 0;
//continue;
break;
}
if (strstr($line, 'SNR Margin (dB):')) {
$get_snr = 1;
continue;
}
if (strstr($line, 'Attenuation (dB):')) {
$get_att = 1;
continue;
}
if (strstr($line, 'Output Power (dBm):')) {
$get_power = 1;
continue;
}
if (strstr($line, 'Attainable Rate (Kbps):')) {
$get_att_rate = 1;
continue;
}
if (strstr($line, 'Rate (Kbps):')) {
$get_rate = 1;
continue;
}
}
if ($u_snr == ' ') $u_snr = 0;
if ($d_snr == ' ') $d_snr = 0;
if ($u_att == ' ') $u_att = 0;
if ($d_att == ' ') $d_att = 0;
if ($u_power == ' ') $u_power = 0;
if ($d_power == ' ') $d_power = 0;
if ($u_att_rate == ' ') $u_att_rate = 0;
if ($d_att_rate == ' ') $d_att_rate = 0;
if ($u_rate == ' ') $u_rate = 0;
if ($d_rate == ' ') $d_rate = 0;
return array($u_snr, $d_snr,
$u_att, $d_att,
$u_power, $d_power,
$u_att_rate, $d_att_rate,
$u_rate, $d_rate);
}

?>
 
Del.icio.us Furl HEMiDEMi Technorati MyShare
commons icon [1] cacti setup [ 回覆 ]

太精彩了 請問學長你那個adslspeed數據如何抓的
感激不盡!!

commons icon [2] [ 回覆 ]

cacti 中自己設定一個 script/command 來抓資料. 寫一個 php script, telnet 到 ATU-R 抓數字. 這樣子就可以了.

commons icon [3] cacti setup [ 回覆 ]

不好意思學長 ATU-R沒密碼怎麼telnet?
還有ATU-R 用snmpwalk 測過沒跑snmp 這樣還有解嗎
謝謝!!

commons icon [4] [ 回覆 ]

沒密碼, 到網路找看看能不能找到吧. 如果真的沒有, 應該看不到連線的速度.
如果 snmp 沒開, 會抓不到流量吧. 改抓與 ATU-R 相連的那張網卡的流量應該也可以.

commons icon [5] cacti setup [ 回覆 ]

報告學長你的意思是說 不能直接抓就抓最近的是吧
以公司的環境應該是抓router的serial port

那請問 script可以照你之前 題的
#!/bin/bash
# chk_adsl: check the status of ADSL and change routing table
# SNMP tree
SNMP_KEY="interfaces.ifTable.ifEntry.ifOperStatus.20"
假設我接的機器網卡
[root@linux-7F peter]# snmpwalk -v 1 192.168.1.73 -c public interfaces.ifTable.ifEntry.ifOperStatus
IF-MIB::ifOperStatus.1 = INTEGER: up(1)
IF-MIB::ifOperStatus.2 = INTEGER: up(1)

IF-MIB::ifDescr.1 = STRING: en0; Product: DEC 21143 PCI Fast Ethernet Controller
Manufacturer: not available! Part Number: -- FRU Number: not available!
IF-MIB::ifDescr.2 = STRING: lo0

(網卡的en0的index為 1)
所以還是可以適用你的script是不是?
----------------
第一種方法裡 snmp trap...

#然後在 192.168.1.254 機器上安裝 snmptrapd, 修改 /etc/snmp/snmptrapd.conf
加上下面兩行:

traphandle .1.3.6.1.6.3.1.1.5.2 /usr/local/bin/adsl_up
traphandle .1.3.6.1.6.3.1.1.5.3 /usr/local/bin/adsl_down

請問這個OID是哪裡得來?

以下是公司R6的數據
[root@linux-7F peter]# snmpwalk -v 1 192.168.1.73 -c public |more
SNMPv2-MIB::sysDescr.0 = STRING: IBM PowerPC CHRP Computer
Machine Type: 0x0800004c Processor id: 000002474C00
Base Operating System Runtime AIX version: 04.03.0003.0000
TCP/IP Client Support version: 04.03.0003.0000
SNMPv2-MIB::sysObjectID.0 = OID: SNMPv2-SMI::enterprises.2.3.1.2.1.1.3

若我要監看R6是不是把 .1.3.6.1.6.3.1.1.5.2
換成.2.3.1.2.1.1.3 ?
那script 是否也一樣
不好意思 初學snmp問題很多 請見諒!!

commons icon [6] [ 回覆 ]

如果你那張網卡確定只連 ATU-R, 就表示上頭的流量就是 ADSL 的流量. 否則就只是部分的流量. 如果你的 ATU-R 是一堆機器都直接連過去的, 就必須抓所有這些機器的流量. (一般來說, 如果是這樣, 你就忘了這回事吧. 如果這資料對你而言很重要, 可以花錢請 ISP 提供, 或換台你知道連線密碼, 可以使用 snmp 的 ATU-R 吧)

OID 的資料請到 net-snmp 的網站查. (而且, 如果沒有 snmp 的功能, 會送出 snmp trap 出來嗎? 不是很奇怪嗎? 你一定是知道密碼才能進入該設定畫面, 指定 trap 要送到那個 ip, 否則光用想的, 機器也不會送出 trap 出來的)

commons icon [7] cacti setup [ 回覆 ]

謝謝 學長我上網已經找到tecom ATU-R的密碼了
發現我的512/512 ADSL 居然qos沒打開 我可以自己開嗎 還有snmp trap已經打開了!!

實做一下 有問題再來請教!!

commons icon [8] 12M最近跟你的一樣情況 [ 回覆 ]

請問一下 那個script 可以分享一下嗎 我家最近的adsl 12m也是類似這樣

迴響
暱稱:
標題:
個人網頁:
電子郵件:
authimage

迴響

  

Bad Behavior 已經阻擋了 57 個過去 7 天試圖闖關的垃圾迴響與引用。
Power by LifeType. Template design by JamesHuang. Valid XHTML and CSS