全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:7473
推到 Plurk!
推到 Facebook!

Windows socket error 無法在通訊端執行操作 , 因為系統緩衝區空間不足 , 或是佇列已滿.

答題得分者是:RaynorPao
2007
中階會員


發表:54
回覆:90
積分:98
註冊:2008-08-12

發送簡訊給我
#1 引用回覆 回覆 發表時間:2008-10-21 09:38:21 IP:220.132.xxx.xxx 未訂閱
各位大大好:

我遇到的問題和這位大大遇到的問題一樣!!!

ClientSocket連線的問題!?
http://delphi.ktop.com.tw/board.php?cid=168&fid=920&tid=33746

程式有一個 Timer !!
(一)、當 ClientSocket 執行與 Server 連線的指令後 ( ClientSocket->Open(); ),Timer 就開始計時。
(二)、一分鐘後發現沒有連不到 Server 時,ClientSocket->Close(); 。
----> 因為怕 Close(); , ClientSocket 會釋放一些東西,所以等了一分鐘後,再下 Open();

(
三)、二分鐘後,ClientSocket->Open();,Timer 又重新開始計時。
(四)、循環以上(二)(三)的動作。
一直的循環!! 當然連上時,就停止這樣的循環,直到 Disconnect 事件觸發,就再繼續這樣的循環。

但當我故意把 server 關掉,讓這程式一直的這樣的在執行,好像二三天後就會出現跟大大一樣的錯誤訊息。
Windows socket error 無法在通訊端執行操作 , 因為系統緩衝區空間不足 , 或是佇列已滿.(10055),on API connect

因此想說 TClientSocket 是不是有清佇列之類的指令,是不是它一直在 open ~~ open ~~ open 但沒清掉它內部運作的佇列造成的???
各位大大是否有遇過?? 請問要如何解決??
謝謝您們!!


PS:
也參考了 Socket 錯誤碼詳解 這一篇,但還是不知如何解決
http://delphi.ktop.com.tw/board.php?cid=31&fid=77&tid=30956
WSAENOBUFS (10055) 緩衝區過小
WinSock核心無法配置足夠的緩衝區,無法執行該程式。這個錯誤的發生和整個Windows系統資源有關。
如果整個Windows本身可用的資源就很少,所能同時執行的程式也少。也有可能是執行了"不良"的應用程式,
沒有正常的使用和歸還系統資源(如記憶體)。或是某些應用程式的不正常關閉,也會佔用系統資源。
編輯記錄
2007 重新編輯於 2008-10-21 09:40:17, 註解 無‧
2007 重新編輯於 2008-10-21 10:41:26, 註解 無‧
2007 重新編輯於 2008-10-21 10:44:39, 註解 無‧
2007 重新編輯於 2008-10-21 10:45:21, 註解 無‧
RaynorPao
版主


發表:139
回覆:3622
積分:7025
註冊:2002-08-12

發送簡訊給我
#2 引用回覆 回覆 發表時間:2008-10-21 10:29:13 IP:210.208.xxx.xxx 訂閱
建議先試試以下的作法,看看是否可行?
(1)ClientSocket1 程式啟動的時候,先 ClientSocket1->Open();
(2)三分鐘後,Timer1 若檢查到連不上 Server,則先做 ClientSocket1->Close();
(3)再重新做一次 ClientSocket1->Open();
(4)循環以上(2)(3)的動作
------
-- 若您已經得到滿意的答覆,請適時結案!! --
-- 欲知前世因,今生受者是;欲知來世果,今生做者是 --
-- 一切有為法,如夢幻泡影,如露亦如電,應作如是觀 --
2007
中階會員


發表:54
回覆:90
積分:98
註冊:2008-08-12

發送簡訊給我
#3 引用回覆 回覆 發表時間:2008-10-21 10:34:51 IP:220.132.xxx.xxx 未訂閱

謝謝 RaynorPao 大大!!

(2)三分鐘後,Timer1 若檢查到連不上 Server,則先做 ClientSocket1->Close();

這步驟我也有做,只是忘了寫上去!!!


===================引 用 RaynorPao 文 章===================
建議先試試以下的作法,看看是否可行?
(1)ClientSocket1 程式啟動的時候,先 ClientSocket1->Open();
(2)三分鐘後,Timer1 若檢查到連不上 Server,則先做 ClientSocket1->Close();
(3)再重新做一次 ClientSocket1->Open();
(4)循環以上(2)(3)的動作

zhgwbzhd
一般會員


發表:10
回覆:32
積分:18
註冊:2008-07-24

發送簡訊給我
#4 引用回覆 回覆 發表時間:2008-10-21 10:36:26 IP:221.218.xxx.xxx 未訂閱
同意2樓版主的做法。
估計就是沒有關掉髮齣去的socket。
先関再重新打開,比較好!
zhgwbzhd
一般會員


發表:10
回覆:32
積分:18
註冊:2008-07-24

發送簡訊給我
#5 引用回覆 回覆 發表時間:2008-10-21 10:45:30 IP:221.218.xxx.xxx 未訂閱
另外,建議不要一開始open就開始計時。
在返囬錯誤時,也就是錶示連接失敗時,開始計時比較閤理。
RaynorPao
版主


發表:139
回覆:3622
積分:7025
註冊:2002-08-12

發送簡訊給我
#6 引用回覆 回覆 發表時間:2008-10-21 14:52:18 IP:210.208.xxx.xxx 訂閱
(1)理論上應該不會產生這個錯誤,因為當 ServerSocket1 正常運作,且網路也正常的話,ClientSocket1->Open(); 自然可以與 ServerSocke1 建立連線,這個時候才會佔用系統的資源,你可以利用以下的方法驗證(實驗的環境是 Client 和 Server 在同一台主機,且 Server Listen Port 4000):

[code cpp]
// Server 端的程式碼
// Unit1.cpp
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ServerSocket1->Port=4000;
ServerSocket1->Open();
}
//---------------------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
ServerSocket1->Close();
}
//---------------------------------------------------------------------------
[/code]

[code cpp]
// Client 端的程式碼
// Unit1.cpp
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ClientSocket1->Address="127.0.0.1";
ClientSocket1->Port=4000;
ClientSocket1->Open();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
ClientSocket1->Close();
}
//---------------------------------------------------------------------------
[/code]
(2)把以上 Server 端及 Client 端的程式分別 Run 起來之後,先按 Client 端程式的 Button1,若可順利建立連線
(3)開一個命令提示字元視窗(DOS Box),然後執行 Command line: 「netstat -a」,你會發現裡面有兩行,其中「電腦名稱」會是你自己的電腦名稱,而 3397 也會因 Client 端 binding 不同的 Port 而出現其他的數字
[code cpp]
C:\netstat -a
Active Connections
Proto Local Address Foreign Address State
...略...
TCP 電腦名稱:4000 localhost:0 LISTENING
TCP 電腦名稱:3397 localhost:4000 ESTABLISHED
...略...在此區域輸入程式碼

[/code]

(4)以上的兩行,代表 ClientSocket1 binding 3397 Port,連線到 ServerSocket1 Listen 的 4000 Port,而且已經建立連線,這個時候已經佔用系統的資源
(5)接下來,按 Client 端程式的 Button2 結束連線,然後你在命令提示字元視窗(DOS Box),執行 Command line: 「netstat -a」,你會發現裡面的兩行,已經改變
[code cpp]
C:\netstat -a
Active Connections
Proto Local Address Foreign Address State
...略...
TCP 電腦名稱:4000 localhost:0 LISTENING
TCP 電腦名稱:3397 localhost:4000 TIME_WAIT
...略...

[/code]

(6)第二行的 State 從 ESTABLISHED 變成 TIME_WAIT,雖然 ClientSocket1 已經主動結束連線,但是這個 3397 Port 還是會被佔用一段時間,直到作業系統來回收這個已經不使用的 Port,你可以嘗試過幾分鐘之後,在命令提示字元視窗(DOS Box),執行 Command line: 「netstat -a」,你會發現裡面的第二行會自動消失,代表已經沒有佔用系統資源
(7)接著你把 Server 端的程式關閉,然後在 Client 端程式按 Button1,可能會出現 10061 的錯誤訊息,這是正常的,因為沒有辦法建立連線,然後在命令提示字元視窗(DOS Box),執行 Command line: 「netstat -a」,你會發現裡面的兩行並不存在,代表沒有佔用任何系統資源
(8)從以上 (1)~(7) 的實驗結果來看,假如你的 Timer 每 3 分鐘執行一次,若 ClientSocket1 沒有辦法與 ServerSocket1 建立連線,理論上應該不會佔用系統的資源;而每一個連線斷線的話,作業系統也會回收這些沒有使用的 Port
(9)因此,我建議你是否可以建立像以上這樣的 Client 及 Server 專案,再加上你原本的 Timer 機制,其他的程式碼不要加進來,然後就這樣 Run 個幾天看看,還會不會有同樣的情形發生,如果不會發生的話,那就代表是其他的程式碼造成的,或許要好好檢查程式碼中對記憶體的操作,會比較妥當
------
-- 若您已經得到滿意的答覆,請適時結案!! --
-- 欲知前世因,今生受者是;欲知來世果,今生做者是 --
-- 一切有為法,如夢幻泡影,如露亦如電,應作如是觀 --
2007
中階會員


發表:54
回覆:90
積分:98
註冊:2008-08-12

發送簡訊給我
#7 引用回覆 回覆 發表時間:2008-10-28 10:04:52 IP:220.132.xxx.xxx 未訂閱
謝謝大大的回應!!

這幾天嚐試的寫一個單純的測試程式,但還是會出現此問題。

程式如下:

http://delphi.ktop.com.tw/download.php?download=upload/49067209e07dd_ClientSocket.rar

不知大大是否能幫小弟找出問題!!

因為主要是在連不到對方的情況下發生,所以程式中故意連到一個對方(SERVER)不開啟的 PORT 。

謝謝!!

===================引 用 RaynorPao 文 章===================
(1)理論上應該不會產生這個錯誤,因為當 ServerSocket1 正常運作,且網路也正常的話,ClientSocket1->Open(); 自然可以與 ServerSocke1 建立連線,
這個時候才會佔用系統的資源,你可以利用以下的方法驗證(實驗的環境是 Client 和 Server 在同一台主機,且 Server Listen Port 4000):

[code cpp]
// Server 端的程式碼
// Unit1.cpp
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ServerSocket1->Port=4000;
ServerSocket1->Open();
}
//---------------------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
ServerSocket1->Close();
}
//---------------------------------------------------------------------------
[/code]

[code cpp]
// Client 端的程式碼
// Unit1.cpp
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ClientSocket1->Address="127.0.0.1";
ClientSocket1->Port=4000;
ClientSocket1->Open();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
ClientSocket1->Close();
}
//---------------------------------------------------------------------------
[/code]
(2)把以上 Server 端及 Client 端的程式分別 Run 起來之後,先按 Client 端程式的 Button1,若可順利建立連線
(3)開一個命令提示字元視窗(DOS Box),然後執行 Command line: 「netstat -a」,你會發現裡面有兩行,其中「電腦名稱」會是你自己的電腦名稱,而 3397 也會因 Client 端 binding 不同的 Port 而出現其他的數字
[code cpp]
C:\netstat -a
Active Connections
Proto Local Address Foreign Address State
...略...
TCP 電腦名稱:4000 localhost:0 LISTENING
TCP 電腦名稱:3397 localhost:4000 ESTABLISHED
...略...在此區域輸入程式碼

[/code]

(4)以上的兩行,代表 ClientSocket1 binding 3397 Port,連線到 ServerSocket1 Listen 的 4000 Port,而且已經建立連線,這個時候已經佔用系統的資源
(5)接下來,按 Client 端程式的 Button2 結束連線,然後你在命令提示字元視窗(DOS Box),執行 Command line: 「netstat -a」,你會發現裡面的兩行,已經改變
[code cpp]
C:\netstat -a
Active Connections
Proto Local Address Foreign Address State
...略...
TCP 電腦名稱:4000 localhost:0 LISTENING
TCP 電腦名稱:3397 localhost:4000 TIME_WAIT
...略...

[/code]

(6)第二行的 State 從 ESTABLISHED 變成 TIME_WAIT,雖然 ClientSocket1 已經主動結束連線,但是這個 3397 Port 還是會被佔用一段時間,直到作業系統來回收這個已經不使用的 Port,你可以嘗試過幾分鐘之後,在命令提示字元視窗(DOS Box),執行 Command line: 「netstat -a」,你會發現裡面的第二行會自動消失,代表已經沒有佔用系統資源
(7)接著你把 Server 端的程式關閉,然後在 Client 端程式按 Button1,可能會出現 10061 的錯誤訊息,這是正常的,因為沒有辦法建立連線,然後在命令提示字元視窗(DOS Box),執行 Command line: 「netstat -a」,你會發現裡面的兩行並不存在,代表沒有佔用任何系統資源
(8)從以上 (1)~(7) 的實驗結果來看,假如你的 Timer 每 3 分鐘執行一次,若 ClientSocket1 沒有辦法與 ServerSocket1 建立連線,理論上應該不會佔用系統的資源;而每一個連線斷線的話,作業系統也會回收這些沒有使用的 Port
(9)因此,我建議你是否可以建立像以上這樣的 Client 及 Server 專案,再加上你原本的 Timer 機制,其他的程式碼不要加進來,然後就這樣 Run 個幾天看看,還會不會有同樣的情形發生,如果不會發生的話,那就代表是其他的程式碼造成的,或許要好好檢查程式碼中對記憶體的操作,會比較妥當
RaynorPao
版主


發表:139
回覆:3622
積分:7025
註冊:2002-08-12

發送簡訊給我
#8 引用回覆 回覆 發表時間:2008-10-28 12:06:15 IP:210.208.xxx.xxx 訂閱
(1)我花了一點時間看你的程式,跟我之前建議你用來釐清問題,較簡單版本的專案,似乎也差異太大了吧
(2)裡面用了三個 Timer 來控制 TClientSocket Array (size 250),這樣當然比較不容易找到問題,而我也沒有足夠的時間幫你看完程式
(3)不過依照你的描述,在連線一直無法建立的情形持續一段時間後,就會發生你所說的問題,我看到你的程式碼在 Timer 裡動態 new TClientSocket,但是無法連線的時候,卻沒有把它 delete,也就是在 try 裡面 new,若 catch 到 exception 的話,要把它 delete 掉,這樣才不會造成系統資源的佔用,直到系統資源被耗盡為止
(4)建議你再重新調整你的程式架構,調整完之後,要做驗證的工作,要如何驗證呢?很簡單,就是把你的程式 run 起來之後,然後把工作管理員打開,觀察你的執行檔的記憶體使用情況,如果記憶體的使用情況會一直持續成長,那代表你的程式還是有問題,請再做修正,一直反覆此作法,直到記憶體不會一直持續成長為止;否則,你的問題是無法避免的
------
-- 若您已經得到滿意的答覆,請適時結案!! --
-- 欲知前世因,今生受者是;欲知來世果,今生做者是 --
-- 一切有為法,如夢幻泡影,如露亦如電,應作如是觀 --
系統時間:2017-12-17 12:21:24
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!