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

在Delphi中讀取局域網內另一台電腦的螢幕

 
conundrum
尊榮會員


發表:893
回覆:1272
積分:643
註冊:2004-01-06

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-05-30 00:42:40 IP:61.64.xxx.xxx 未訂閱
在Delphi中讀取局域網內另一台電腦的螢幕 [摘要] 編寫過Winsock應用程式的程式師都知道,編寫Winsock應用程式絕不是一件輕而易舉的事,您不得直接與複雜的Winsock中的Api打交道,幸運的是,Delphi4中的Tclientsocket 和Tserversocket封裝了Windows中有關的Api,大為簡化了對Winsock的訪問,使得我們能夠非常輕易的編寫Winsock應用程式。本文通過一個讀取局域網內另一台電腦螢幕的示例,來介紹如何用Delphi編寫Winsock應用程式。 在單位做過網管的人都可能有這樣的經歷,通過電話“遙控”指導別人操作是一件多麼心煩的事,而且我又是一個懶人,不想天天為一點小事從樓頂跑到樓下,怎麼辦呢?編一個讀取另一台電腦螢幕的程式怎麼樣?不就直觀多了。在局域網內進行通信,最好的選擇當然是用Winsock,編寫過Winsock應用程式的程式師都知道,編寫Winsock應用程式絕不是一件輕而易舉的事,您不得直接與複雜的Winsock中的Api打交道,幸運的是,Delphi4中的Tclientsocket 和Tserversocket封裝了Windows中有關的Api,大為簡化了對Winsock的訪問,使得我們能夠非常輕易的編寫Winsock應用程式。儘管如此,最好還是對Winsock有一些瞭解,在這裏我就不再贅述,您可以找些書自己看看。 通過網路傳輸資料,您至少需要一對Socket,其中一個在用戶端,另一個在服務端,一旦用戶端與服務端的socket建立起連接,就可以相互通信了,用Socket建立連接是建立在Tcp/ip基礎上的,同時也支援ipx/spx等相關協定。在Delphi中 分別用Tclientsocket 和Tserversocket來操縱用戶端與服務端Socket的連接和通信。要說明的是,這兩個元件用於管理伺服器與客戶的連接,本身並不是Socket物件,操縱Socket物件的是TcustomwinSocket,如Tclientwinsocket、 Tserverclientwinsocket、Tserverwinsocket。 一、Tclientsocket元件: 把一個Tclientsocket加到Form上,應用程式就變為一個Tcp/ip客戶,就可以用Tclientsocket來操縱用戶端的Socket物件。 要建立與伺服器的連接,應先指定要連接的伺服器。指定伺服器有兩種方式,一種是設置Host屬性指定伺服器的主機名,如http://www.inprise.com或局域網中的機器名,這種方式直觀,但要進行功能變數名稱解析,速度會稍慢一些;另一種方法是設置Adress屬性指定主機的ip位址,如130.0.1.1。這兩種方法是等價的,但如果同時設置了Host和Adress,Delphi將只使用Host屬性。 然後要指定連接伺服器的埠號,這裏也有兩種方式,一是設置Service使用默認埠號,一是直接設置Port埠號,在1024以下的埠號中,很多都已經分配出去了,如FTP的埠為20和21,SMTP的埠是25,WEB伺服器的埠為80等,為防止無意間的衝突,建議在編制自已的應用程式時,最好將Port設為1024以上。如果同時設置了Service和port,Delphi將使用Service默認的埠。 指定好伺服器和埠號後,調用open方法或將Active屬性設為True,用戶端的Socket就會向服務端的Socket提出連接請求,如果此時服務端處於監聽狀態,就會自動接受請求建立連接,建立連接時,會觸發其Onconnet事件。需要斷開連接時,只需要調用close方法或將Active屬性設為False,此時會觸發ondisconnet事件。 二、Tserversocket元件: 同Tclientsocket一樣,建造一個伺服器,只需要將一個Tserversock元件放在Form即可。 服務端的socket物件管理起來較為複雜。當伺服器處於監聽狀態,此時服務端的socket物件用Tserversocket來操縱;當客戶提出請求,伺服器回應請求並建立了連接,此時用Tserverclientwinsocket來操縱服務端Socket與用戶端的Socket的連接。 要使伺服器處於監聽狀態,必須先指定埠號,當然,應該和用戶端的埠號相同。然後調用open方法或Active屬性設為True。 三、通信: 一旦建立起客戶與伺服器的連接後,就可以進行相互間的通信了。Delphi為Tserversocket和Tclientsocket提供了幾個通信用的方法,用sendtext發送本本資訊,用sendstream發送流,用SendBuf發送指定長度的資料。 需要注意的是,由於windows默認緩衝區大小為4K,所以當發送長於4K的資訊時,比如,從服務端向用戶端發送的一個二進位流,在服務端只需要用 Socket.SendStream()就行了,而在用戶端就不一樣,它將多次觸發onread事件,而Delphi又沒有定義如“onreadend”之類的事件,因此,必須在接收時程式師自己對資料進行組裝。本文採取的方法是先將流長度發給用戶端,然後發送流,用戶端將接收的資料寫進一個流中,當流長度等於服務端發回的長度時,就表明用戶端已接收完畢了。對服務端來說,做為sendstream參數的流,會為Socket 所“擁有”,Socket物件結束時,它也將結束,而不要自己去釋放它,否則,會觸發一個異常。 同樣,當發送的文本小於4K,例如在用戶端程式中進行如下調用時 clientsocket1.Socket.SendText(‘gets‘); clientsocket1.Socket.SendText(‘gets‘); clientsocket1.Socket.SendText(‘gets‘); 服務端接收時會出現getsgets之類的現象,這可能是因為當緩衝區內的資料還未發送完時,又將新的文本放入緩衝區,電腦把它也當成同一批資料進行處理的緣故。為避免這個現象的發生,在程式內可採用一來一回“拋球”式的做法: 用戶端 服務端 clientsocket1.Socket.SendText(‘data1‘) socket.ReceiveText; socket.sendtext(‘ok‘); socket.receivetext; clientsocket1.Socket.SendText(‘ data2‘) socket.ReceiveText; socket.sendtext(‘end‘); socket.receivetext; 在另一台電腦上運行服務端程式後,在您的用戶端程式上文本框內輸入該電腦名,接“連接”,按“取圖”,如何,對方電腦的螢幕一覽無餘了吧。以下是程式的全部源代碼,本程式在NT4.0、Win95、Win98、局域網內運行通過,當然,windows必須得裝tcp/ip協定,而且必須有動態分配的或指定的ip地址。 如果您覺邊看邊“指揮”還是比較麻煩,您還可以對image1上的鍵盤、滑鼠事件進行分析,然後發給服務端,服務端接收後,再進行同樣的操作,這樣您就可以不用麻煩操作員了。利用Delphi的Tclientsocket 和Tserversocket,還可以完成諸如檔複製、網上聊天、ICQ等應用程式的開發,實現起來都很簡單,你可以自由的發揮出你的想像力,編寫出更富魅力的程式來。 用戶端程式: unit cmain; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ScktComp, StdCtrls, ExtCtrls,jpeg; type TForm1 = class(TForm) Panel1: TPanel; ScrollBox1: TScrollBox; Image1: TImage; Button1: TButton; Edit1: TEdit; Button2: TButton; ClientSocket1: TClientSocket; Label1: TLabel; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket); procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket); procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } public { Public declarations } end; var Form1: TForm1; c:longint; m:tmemorystream; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); begin try clientsocket1.Close; clientsocket1.Host:=edit1.text; clientsocket1.Open; //連接服務端 except showmessage(edit1.text #13#10 ‘未開機或未安裝服務程式‘); end; end; procedure TForm1.Button2Click(Sender: TObject); begin clientsocket1.Socket.SendText(‘gets‘); //發送申請,通知服務端需要螢幕圖像 end; procedure TForm1.ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket); begin caption:=‘連接到‘ edit1.text; end; procedure TForm1.ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); begin caption:=‘連接‘ edit1.text ‘失敗‘; showmessage(edit1.text #13#10 ‘未開機或未安裝服務程式‘); errorcode:=0; end; procedure TForm1.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket); var buffer:array [0..10000] of byte; //設置接收緩衝區 len:integer; ll:string; b:tbitmap; j:tjpegimage; begin if c=0 then //C為服務端發送的位元組數,如果為0表示為尚未開始圖像接收 begin ll:=socket.ReceiveText; c:=strtoint(ll); //設置需接收的位元組數 clientsocket1.Socket.SendText(‘okok‘); //通知服務端開始發送圖像 end else begin //以下為圖像資料接收部分 len:=socket.ReceiveLength; //讀出包長度 socket.ReceiveBuf(buffer,len); //接收資料包並讀入緩衝區內 m.Write(buffer,len); //追加入流M中 if m.Size>=c then //如果流長度大於需接收的位元組數,則接收完畢 begin m.Position:=0; b:=tbitmap.Create; j:=tjpegimage.Create; try j.LoadFromStream(m); //將流M中的資料讀至JPG圖像物件J中 b.Assign(j); //將JPG轉為BMP Image1.Picture.Bitmap.Assign(b); //分配給image1元件 finally //以下為清除工作 b.free; j.free; clientsocket1.Active:=false; clientsocket1.Active:=true; m.Clear; c:=0; end; end; end; end; procedure TForm1.FormCreate(Sender: TObject); begin m:=tmemorystream.Create; end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin m.free; ClientSocket1.Close; end; end. 服務端程式: unit smain; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ScktComp,jpeg; type TForm1 = class(TForm) ServerSocket1: TServerSocket; procedure ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; m1:tmemorystream; implementation {$R *.DFM} procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket); var s,s1:string; desk:tcanvas; bitmap:tbitmap; jpg:tjpegimage; begin s:=socket.ReceiveText; if s=‘gets‘ then //用戶端發出申請 begin bitmap:=tbitmap.Create; jpg:=tjpegimage.Create; desk:=tcanvas.Create; //以下代碼為取得當前螢幕圖像 desk.Handle:=getdc(hwnd_desktop); m1:=tmemorystream.Create; //初始化流m1,在用sendstream(m1)發送流後, //它將保留到socket對話結束, //不能用手工free掉,否則會觸發異常 with bitmap do begin width:=screen.Width; height:=screen.Height; canvas.CopyRect(canvas.cliprect,desk,desk.cliprect); end; jpg.Assign(bitmap); //將圖像轉成JPG格式 jpg.SaveToStream(m1); //將JPG圖像寫入流中 jpg.free; m1.Position:=0; s1:=inttostr(m1.size); Socket.sendtext(s1); //發送圖像大小 end; if s=‘okok‘ then //用戶端已準備好接收圖像 begin m1.Position:=0; Socket.SendStream(m1); //發送JPG圖像 end; end; procedure TForm1.FormCreate(Sender: TObject); begin ServerSocket1.open; end; end.
系統時間:2024-05-19 4:31:02
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!