關於Twinsoketstream類的write函數 |
|
AB
高階會員 發表:166 回覆:262 積分:125 註冊:2003-08-21 發送簡訊給我 |
關於Twinsoketstream類的write函數
http://www.powerba.com/develop/delphi/article/20011010012.htm
我曾在DELPHI大富翁上發表了以下問題,但回應寥寥。
問題:
我用delphi 3.0c/s 編寫Email用戶端程式,在程式中使用
Twinsocketstream傳送資訊,我先把信件資訊存到一個
stream中,再用Twinsocetstream類函數copyfrom,把字元傳
到Soket上。但是當資訊大於2k或3k時,系統就崩潰,
出現藍屏, 我察看了Twinsocketstream的源碼,發現
wirte函數是完成copyfrom功能的主要函數,
在write函數裏有一句代碼是:
if not WriteFile(FSocket.SocketHandle, Buffer, Count,
Integer(Result), @Overlapped) and (GetLastError <>
ERROR_IO_PENDING) then
據我理解這裏使用了非同步寫操作,關鍵是Overlapped
的使用,當我把Overlapped參數改d零,並對後面
有關非同步寫操作的代碼進行了修改,即改d
阻塞同步寫操作,再次運行程式,轉送一個1M多
的Attach file ,也能運行通過。
我不知道這是d甚l,請各位給我指教,並詳細
講一下wirtefile API函數裏的overlap參數的具體含義
與用法。 有關此問題的補充: 這兩天,過節有了充裕時間來研究這個問題,我又仔細地分析了twinsocketstre
am.write
函數的源代碼,發現它的代碼與twinsocketstream.read函數的代相似,但是write與read
相比在GetOverlappedResult(FSocket.SocketHandle, Overlapped, Integer(Re
sult), false);語
句後少了一個fevent.resetevent;語句。這個語句是用來把時間event設d不發信
號,阻止
與此事件有關的線程(即writefile函數)運行,據我所知,winsocket自己不負
責處理
多線程之間的重入,這必須由程式師自己解決,如果write函數沒有fevent.rese
tevent ,
那l當我的程式繼續對socket進行操作,例如讀socket時,writefile函數也同時
在對
socket進行寫操作,這就發生了重入,從而使得winsocket崩潰,即使能關閉有問
題的
程式,winsocket也無法使用了,除非重均C
這種分析能夠解釋我在編程中碰到的現象。
我把fevent.resetevent加到write函數中去,用我編的email程式發送幾個長達1
M的附件,
發現在發送一個附件時,程式能夠正常運行,當我的程式創建了四個線程,同時
發送四
個附件時,老問題又出來了。看來真是好事多磨,我發現
if FEvent.WaitFor(FTimeOut) <> wrSignaled then
Result := 0;
也有上述的問題,我在程式中設定的ftimeout是2000,即2秒,當我同時發送多
個附
件時,socket有些繁忙,2秒過後可能writefile還沒有完成操作,這個判斷就成
立了,
但是這裏面少了fevent.resetevent,於是用樣的問題就又出來了。解決的辦法是
,加入
fevent.resetevent。不過如果想讓程式正常運行必須加大ftimeout值,這個值在
編程時應
預留介面,讓使用者根據網路情況自己設定。
綜上所述,delphi3/cs在此有bug ,不知delphi4.0是否加以了改進。 另外,我認
d這裏
雖然使用了writefile的非同步功能,但是並沒有充分利用非同步特性,而只是簡單地
有waitfor
進行等待,這與twinsocketstream本身是阻塞的socket有關,這裏使用了非同步寫
操作唯
一的作用是引入了timeout, 避免因網路阻塞writefile長時間無法返回,給程式
一個撤
銷寫操作的機會。
最後我把修改後的write 與read函數附在這裏,請大家參考。
談了這l多,不知道自己對不對,請萓麆炊漇教。 function TWinSocketStream.Read(var Buffer; Count: Longint): Longint;
var
Overlapped: TOverlapped;
ErrorCode: Integer;
begin
FSocket.Lock;
try
FillChar(OVerlapped, SizeOf(Overlapped), 0);
Overlapped.hEvent := FEvent.Handle;
if not ReadFile(FSocket.SocketHandle, Buffer, Count, Integer(Resul
t),
@Overlapped) and (GetLastError <> ERROR_IO_PENDING) then
begin
ErrorCode := GetLastError;
raise ESocketError.CreateFmt(sSocketIOError, [sSocketRead, Error
Code,
SysErrorMessage(ErrorCode)]);
end;
if FEvent.WaitFor(FTimeOut) <> wrSignaled then
begin
Result := 0;
FEvent.ResetEvent;
end
else
begin
GetOverlappedResult(FSocket.SocketHandle, Overlapped, Integer(Re
sult), False);
FEvent.ResetEvent;
end;
finally
FSocket.Unlock;
end;
end; function TWinSocketStream.Write(const Buffer; Count: Longint): Longint
;
var
Overlapped: TOverlapped;
ErrorCode: Integer;
begin
FSocket.Lock;
try
FillChar(OVerlapped, SizeOf(Overlapped), 0);
Overlapped.hEvent := FEvent.Handle;
if not WriteFile(FSocket.SocketHandle, Buffer, Count, Integer(Resu
lt),
@Overlapped) and (GetLastError <> ERROR_IO_PENDING) then
begin
ErrorCode := GetLastError;
raise ESocketError.CreateFmt(sSocketIOError, [sSocketWrite, Erro
rCode,
SysErrorMessage(ErrorCode)]);
end;
if FEvent.WaitFor(FTimeOut) <> wrSignaled then
begin
Result := 0;
fevent.resetevent;
end
else
begin
GetOverlappedResult(FSocket.SocketHandle, Overlapped, Integer(Re
sult),false);
FEvent.ResetEvent;
end;
finally
FSocket.Unlock;
end;
end;
|
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |