socket程式設計小問題:地址已經被使用——Address already in use
很多socket程式設計的初學者可能會遇到這樣的問題:如果先ctrl+c結束伺服器端程式的話,再次啟動伺服器就會出現Address already in use這個錯誤,或者你的程式在正常關閉伺服器端socket後還是有這個問題。正如下面的這段簡單的socket程式。
server.c
client.c
在成功的運行了第一次之後,當你再次啟動伺服器端程式時,./server就變得邪惡起來,在bind()這個函式中居然出現了Address already in use這個錯誤。
然後你開始迷惑了,難道是忘記將socket給關閉了,或是關閉socket的順序不對?經過種種猜測與試驗,你發現問題毫無進展......過了一會,當你再次抱著試試看的態度重新在linux的“黑色終端”中輸入./server時,程式居然運行了,什麼情況?究其原因,是socket選項在搗鬼。下面是IBM官網上對這一情況的具體解釋,參見
bind 普遍遭遇的問題是試圖繫結一個已經在使用的埠。該陷阱是也許沒有活動的套接字存在,但仍然禁止繫結埠(bind 返回 EADDRINUSE),它由 TCP 套接字狀態 TIME_WAIT 引起。該狀態在套接字關閉後約保留 2 到 4 分鐘。在 TIME_WAIT 狀態退出之後,套接字被刪除,該地址才能被重新繫結而不出問題。
等待 TIME_WAIT 結束可能是令人惱火的一件事,特別是如果您正在開發一個套接字伺服器,就需要停止伺服器來做一些改動,然後重啟。幸運的是,有方法可以避開 TIME_WAIT 狀態。可以給套接字應用 SO_REUSEADDR 套接字選項,以便埠可以馬上重用。
考慮清單 3 的例子。在繫結地址之前,我以 SO_REUSEADDR 選項呼叫 setsockopt。為了允許地址重用,我設定整型引數(on)為 1 (不然,可以設為 0 來禁止地址重用)。
按照IBM的做法,我重新改寫了server.c的程式碼。
server.c
這次,讓我們再次反覆的啟動伺服器,盡情的在“黑窗戶”裡面輸入./server ./server ./server ......伺服器的程式好像突然間變乖了,呵呵,童鞋們,為自己的成就慶祝吧!!!