電腦不乖 – HTTP 與印表機問題

前陣子某一天, 我的網站突然不能用了. 按照先前的印象, 首先檢查寬頻連線、防火牆、HTTP port. 果然 HTTP port (80) 不知被誰佔用了?

網路上有很多這類文章, 隨便 Google 都可以查得到, 所以我前一次把問題解決後也沒去記用法. 不過問題再度發生的時候就糗了, 又要重頭 Google. 網路上的 SOP 是執行

netstat -ano

看 0.0.0.0:80 是哪個 PID 占用? 高手 [1] 會用

netstat -nao | find “0.0.0.0:80″

這樣就會自動撈出來 PID. 有了 PID, 還要找是哪個程式在用, 同樣參考 [1], 應該打

tasklist /fi “pid eq 1234"   (1234 是舉例)

如果這程式不是 Apache, 而是像是慣犯 Skype…等等在用, 就可以把它先 kill 掉. 比較麻煩的是看到 pid =4 , 這是系統自己占用的, 網路上的解法 [2] 是把 http service 停掉, 並且把開機時的 http service 設為 disabled.

運氣好的話, 執行

net stop http

這時用到 http 的程式就會一隻一隻停掉. 但我的運氣不太好, 停到 http service 的時候, 就會跟我說 http 正在開啟或關閉中, 無法停止服務. 我猜是因為 apache 還在用它的關係. 此時死馬當作活馬醫, 繼續打

Sc config http start= disabled

然後重新開機, 基本上就修復了. 雖然中間反覆了幾次修些小問題, 但這招是靈光的. But….

用了這招之後, printer 就爛掉了. 我的 printer 是 MFP, 所以它還可以掃描, 但是不能印東西了! 這實在讓我很不方便. 一開始也沒聯想到是關閉了 http 的關係. 根據正常的直覺, 當然是先檢查 spooler 啊! (看我大學系統程式學得多精實, 哈!)

當我去服務裡面啟動 spooler, 它彈給我一個 error 1068! 1068 的錯誤代碼是相依於 spooler 的服務無法啟動. 到處看了幾篇文章, 原來 spooler 的相依性在這裡.

print-spooler

把 RPC, DCOM Server Process Launcher, 甚至是網路上 [3] 有人建議的 WINHTTP Web Proxy Auto-Discovery Service 都檢查了. 它們都是正常的! 所以…元凶還是我自己啊! 赫然想起我前一陣子把 http 設為 disabled 了.

因此, 重來一次, 這次把它設為… 

net stop http

Sc config http start= boot

哇! 不行, 設 auto..也不行! 設 delayed-auto …耶! 可以了!

Sc config http start= delayed-auto

重新開機, 此時 spooler 可以運作了. 由於 bug 發生的症狀是: 想要印東西時, word 找不到印表機. 因此我趕快新增印表機!

搜尋新增裝置…找不到! 再試一次…還是找不到! 莫非….

原來不用新增, 根本系統就自動找到印表機了. 雖然我看了某篇文章去刪除了 printer 的機碼. 但看來不影響, 它又自動裝上了, 難怪新增不了, 唉! 我真是自作聰明.

為了避免這問題再發生第三次, 乾脆就把前因後果全部火速打成一篇. 希望也能幫助別人解決類似的問題.

[ref]

1. 如何查詢哪個程式佔用了指定Port

2. [Windows] Port 80被佔用導致Apache無法啟動

3.  Printer spooler windows 8 Error 1068: The dependency service or group failed to start.

我讀 «How Networks Work» – 1

這本書是從日文翻譯過來的, 作者是戶根勤. 和這個系列裡面的其他書一樣, 這本書超棒! 它由淺入深地介紹了網路有關的種種東西. 並不會生硬地叫大家從 OSI 開始背誦知識, 而是一步一步地從最基本的網路連接講起.

首先介紹網路如何找到你要的網址開始這個探險旅程. 首先我們會有一個 URL, 然後呢? URL 又可以分為伺服器名稱、目錄與檔案幾個部分. PC 發出一些HTTP 的命令, 像是 GET、POST、PUT 等等. 我們的 PC 上的 web browser 會以 HTTP 特定的格式發出這些命令, HTTP server 收到這些東西之後, 就會給出回應.

但是光知道 HTTP 伺服器的 URL, 又怎麼找到它的 IP address 呢? 這個就要去問 DNS (domain name server).

DNS 查詢的動作, 基本上是一個名稱的解析 (name resolution、DNS resolver), 用 Socket library 就可以呼叫解析器.

<記憶體區域> = gethostbyname(www.abc.com);

傳回的這一塊記憶體, 裡面就會有 IP address. 當然, 中間的過程牽涉到 web 程式 call Socket library 裡面的 gethostbyname(), 而這隻 function 又會去 call OS 內部的 TCP/IP module, TCP/IP module 去 call LAN 網卡驅動程式, 底下才是網卡去和伺服器溝通.

世界上有不同等級的 DNS, 畢竟不是每個 DNS 都放置了全世界的 IP address 與 URL 的對應表. 不知道的東西, 就會層層回報到根網域, 據說這個等級的 DNS 全世界只有 13 部.

書中又特別強調: Socket library 和 socket 是不一樣的, socket 是一個插槽, 相當於一個check in 的動作. 帶著 IP address 和 port number check in 之後就拿到描述器, 相當於是旅館的預約號碼或是房間號碼.

無論在應用程式端 (Web browser 等等) 或是伺服器端, 都會有產生 socket 的動作, 而各自拿到描述器. 應用程式端的描述器變成 connect() 指令的參數, 而伺服器端的描述器則變成 bind() 指令的參數. Bind() 功能是瀏覽器所沒有的, 它會檢查每個 port 所註冊的伺服器程式各自是甚麼? 接著開始 listen().

應用程式以 connect() 來連接伺服器, 跟伺服器說房號 XXX 的客人來了, 伺服器就依據 port對應到的程式來 accept() 這個 connect(). 並且關掉現在的描述器, 產生新的描述器. 我們可想像是把預約號碼換成了房間號碼.

當應用程式 write() 資料過來後, 伺服器就用 read() 來接收, 應用程式送完資料後 close(), 伺服器也 close().

以上就是第一章的重點, 是不是還挺有趣的呢?