[要約] Winsock アプリケーションを作成したことのあるプログラマは、Winsock アプリケーションを作成するのが決して簡単な作業ではないことを知っています。幸いなことに、Delphi4 の Tclientsocket と Tserversocket は、Windows の関連する API にアクセスするのを大幅に簡素化します。 Winsock に接続できるため、Winsock アプリケーションを非常に簡単に作成できるようになります。この記事では、LAN 内の別のコンピュータの画面を読み取る例を通して、Delphi を使用して Winsock アプリケーションを作成する方法を紹介します。
職場でネットワーク管理者として働いたことがある人なら誰でも経験があるかもしれません。電話で他人に「遠隔操作」を指示するのはとても面倒ですし、私は怠け者なので逃げたくありません。毎日些細なことでビルの屋上から階下まで行ってどうする?別のコンピュータの画面を読み取るプログラムを書いてみてはどうでしょうか?はるかに直感的です。 LAN 内で通信するには、Winsock を使用するのが最善の選択です。Winsock アプリケーションを作成したことがあるプログラマは、Winsock アプリケーションを作成するのが決して簡単な作業ではないことを知っています。幸いなことに、Tclientsocket で複雑な API を扱う必要はありません。 Delphi4 の Tserversocket は、Windows の関連 API をカプセル化します。これにより、Winsock へのアクセスが大幅に簡素化され、Winsock アプリケーションを非常に簡単に作成できるようになります。それでも、Winsock についてある程度理解することが最善です。ここでは詳しく説明しません。いくつかの本を見つけて読んでください。
ネットワーク経由でデータを送信するには、少なくとも 1 組のソケットが必要です。クライアントとサーバーのソケットが接続を確立すると、ソケットを使用して相互に通信できるようになります。 Tcp/ip ベースで確立され、ipx/spx およびその他の関連プロトコルもサポートします。 Delphi では、Tclientsocket と Tserversocket を使用して、クライアントとサーバーの Socket 間の接続と通信を制御します。これら 2 つのコンポーネントは、サーバーとクライアント間の接続を管理するために使用されます。Socket オブジェクト自体は、Tclientwinsocket、Tserverclientwinsocket、Tserverwinsocket によって操作されます。
1. Tclientsocket コンポーネント:
Tclientsocket をフォームに追加すると、アプリケーションは Tcp/ip クライアントになり、Tclientsocket を使用してクライアントの Socket オブジェクトを操作できるようになります。
サーバーへの接続を確立するには、まず接続先のサーバーを指定します。サーバーを指定するには 2 つの方法があります。1 つは、Host 属性を設定してサーバーのホスト名 (http://www.inPRise.com など) または LAN 内のマシン名を指定する方法です。ドメイン名の解決が必要ですが、少し遅くなります。別の方法として、Adress 属性を設定してホストの IP アドレス (130.0.1.1 など) を指定します。 2 つのメソッドは同等ですが、ホストとアドレスの両方が設定されている場合、Delphi はホスト プロパティのみを使用します。
次に、サーバーに接続するポート番号を指定する必要があります。1 つはデフォルトのポート番号を使用するように設定する方法で、もう 1 つは 1024 未満のポート番号を直接設定する方法です。 、FTP ポートは 20 と 21、SMTP ポートは 25、WEB サーバー ポートは 80 など、多くのポートが割り当てられています。意図しない競合を防ぐために、独自のアプリケーションをプログラミングするときは、次のようにすることをお勧めします。ポートを 1024 以上に設定するのが最善です。サービスとポートが同時に設定されている場合、Delphi はサービスのデフォルト ポートを使用します。
サーバーとポート番号を指定した後、open メソッドを呼び出すか、Active 属性を True に設定します。この時点でサーバーが待機状態にある場合、クライアントの Socket はサーバーの Socket への接続要求を自動的に受け入れます。接続を確立するためのリクエスト。接続されると、Onconnet イベントがトリガーされます。切断する必要がある場合は、close メソッドを呼び出すか、Active 属性を False に設定するだけで済みます。この時点で、ondisconnet イベントがトリガーされます。
2. Tserversocket コンポーネント:
Tclientsocket と同様に、サーバーを構築するには、Tserversock コンポーネントをフォームに配置するだけです。
サーバー側のソケット オブジェクトの管理はさらに複雑です。サーバーが待機状態にある場合、サーバーのソケット オブジェクトは Tserversocket によって操作され、クライアントが要求を行うと、サーバーは要求に応答して接続を確立します。このとき、サーバー間の接続を操作するために Tserverclientwinsocket が使用されます。ソケットとクライアントのソケット。
サーバーをリスニング状態にするには、最初にポート番号を指定する必要があります。もちろん、それはクライアントのポート番号と同じである必要があります。次に、open メソッドを呼び出すか、Active プロパティを True に設定します。
3. コミュニケーション:
クライアントとサーバー間の接続が確立されると、相互の通信を開始できます。 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');
サーバーが受信すると、getgets などの現象が発生します。これは、バッファー内のデータがまだ送信されていないときに、新しいテキストがバッファーに入れられ、コンピューターがそれを同じデータのバッチとして処理するためであると考えられます。 。この現象の発生を回避するには、プログラム内で「ボールを前後に投げる」方法を使用できます。
クライアントサーバー
clientsocket1.Socket.SendText('data1') ソケット.ReceiveText;
ソケット.sendtext('ok');
ソケット受信テキスト;
clientsocket1.Socket.SendText('data2')
ソケット.ReceiveText;
ソケット.sendtext('終了');
ソケット受信テキスト;
別のコンピュータでサーバー プログラムを実行した後、クライアント プログラムのテキスト ボックスにコンピュータ名を入力し、[接続] をクリックし、[画像を取得] をクリックすると、相手のコンピュータの画面が鮮明に表示されます。以下は、プログラムのソース コード全体です。このプログラムは、NT4.0、Win95、Win98、および LAN で実行できます。もちろん、Windows には TCP/IP プロトコルがインストールされている必要があり、動的に割り当てられるか指定された IP が必要です。住所。
見ながら「コマンド」するのが面倒な場合は、image1 のキーボードとマウスのイベントを解析してサーバーに送信し、サーバーがそれを受信した後に再度同じ操作を実行することもできます。オペレーターは心配する必要はありません。 Delphi の Tclientsocket と Tserversocket を使用すると、ファイルのコピー、オンライン チャット、ICQ などのアプリケーションの開発を完了することもできます。実装は非常に簡単で、想像力を自由に発揮して、より魅力的なプログラムを作成できます。
クライアントプログラム:
単位はメイン。
インタフェース
用途
ウィンドウ、メッセージ、SysUtils、クラス、グラフィックス、コントロール、フォーム、ダイアログ、
ScktComp、StdCtrls、ExtCtrls、jpeg;
タイプ
TForm1 = クラス(TForm)
パネル1: Tパネル;
ScrollBox1:TScrollBox;
画像1: T画像;
ボタン 1: T ボタン;
編集1: TEdit;
ボタン 2: T ボタン;
ClientSocket1: TClientSocket;
ラベル 1: T ラベル;
プロシージャ Button1Click(送信者: TObject);
プロシージャ Button2Click(送信者: TObject);
プロシージャ ClientSocket1Connect(送信者: TObject;
ソケット: TCustomWinSocket);
プロシージャ ClientSocket1Error(送信者: TObject; ソケット: TCustomWinSocket;
エラーイベント: TErrorEvent; var エラーコード: 整数);
プロシージャ ClientSocket1Read(送信者: TObject; ソケット: TCustomWinSocket);
プロシージャ FormCreate(Sender: TObject);
プロシージャ FormClose(Sender: TObject; var Action: TCloseAction);
プライベート
{プライベート宣言}
公共
{公的宣言}
終わり;
変数
フォーム1: TForm1;
c:倍長整数;
m:tメモリストリーム;
実装
{$R *.DFM}
プロシージャ TForm1.Button1Click(送信者: TObject);
始める
試す
clientsocket1.Close;
clientsocket1.Host:=edit1.text;
clientsocket1.Open // サーバーに接続します。
を除外する
showmessage(edit1.text+#13#10+'コンピュータの電源が入っていないか、サービス プログラムがインストールされていません');
終わり;
終わり;
プロシージャ TForm1.Button2Click(送信者: TObject);
始める
clientocket1.Socket.SendText('gets'); // 画面イメージが必要であることをサーバーに通知するリクエストを送信します。
終わり;
プロシージャ TForm1.ClientSocket1Connect(送信者: TObject;
ソケット: TCustomWinSocket);
始める
caption:=「接続先」+edit1.text;
終わり;
プロシージャ TForm1.ClientSocket1Error(送信者: TObject;
ソケット: TCustomWinSocket; エラーイベント: TErrorEvent;
varErrorCode: 整数);
始める
caption:='接続'+edit1.text+'失敗';
showmessage(edit1.text+#13#10+'コンピュータの電源が入っていないか、サービス プログラムがインストールされていません');
エラーコード:=0;
終わり;
プロシージャ TForm1.ClientSocket1Read(送信者: TObject;
ソケット: TCustomWinSocket);
変数
buffer:array [0..10000] of byte; //受信バッファを設定します。
len:整数;
ll:文字列;
b:tビットマップ;
j:tjpegimage;
始める
if c=0 then //C はサーバーによって送信されたバイト数です。0 の場合は、画像の受信がまだ開始されていないことを意味します。
始める
ll:=ソケット.受信テキスト;
c:=strtoint(ll); //受信するバイト数を設定します。
clientocket1.Socket.SendText('okok') // サーバーに画像の送信を開始するように通知します。
それ以外で終了
begin //以下は画像データ受信部分です
len:=socket.ReceiveLength //パケット長を読み取ります。
socket.ReceiveBuf(buffer,len); //データパケットを受信し、バッファに読み込みます。
m.Write(buffer,len); //ストリーム M に追加します。
if m.Size>=c then //ストリーム長が受信バイト数より大きければ受信完了
始める
m.位置:=0;
b:=tbitmap.Create;
j:=tjpegimage.Create;
試す
j.LoadFromStream(m); //ストリーム M のデータを JPG 画像オブジェクト J に読み込みます。
b.Assign(j); //JPGをBMPに変換します。
Image1.Picture.Bitmap.Assign(b); //image1 コンポーネントに割り当てます
最後に // 以下はクリーンアップ作業です
b.無料。
j.無料。
clientsocket1.Active:=false;
clientsocket1.Active:=true;
m.クリア。
c:=0;
終わり;
終わり;
終わり;
終わり;
プロシージャ TForm1.FormCreate(送信者: TObject);
始める
m:=tmemorystream.Create;
終わり;
プロシージャ TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
始める
m.フリー;
ClientSocket1.Close;
終わり;
終わり。
サーバープログラム:
ユニットメイン。
インタフェース
用途
ウィンドウ、メッセージ、SysUtils、クラス、グラフィックス、コントロール、フォーム、ダイアログ、
ScktComp、jpeg;
タイプ
TForm1 = クラス(TForm)
ServerSocket1: TServerSocket;
プロシージャ ServerSocket1ClientRead(送信者: TObject;
ソケット: TCustomWinSocket);
プロシージャ FormCreate(Sender: TObject);
プライベート
{プライベート宣言}
公共
{公的宣言}
終わり;
変数
フォーム1: TForm1;
m1:tmemorystream;
実装
{$R *.DFM}
プロシージャ TForm1.ServerSocket1ClientRead(送信者: TObject;
ソケット: TCustomWinSocket);
変数
s,s1:文字列;
デスク:tキャンバス;
ビットマップ:tビットマップ;
jpg:tjpegimage;
始める
s:=ソケット.受信テキスト;
if s='gets' then //クライアントがリクエストを発行する
始める
ビットマップ:=tbitmap.Create;
jpg:=tjpegimage.Create;
desk:=tcanvas.Create; //次のコードは現在の画面イメージを取得します。
デスクハンドル:=getdc(hwnd_desktop);
m1:=tmemorystream.Create; //sendstream(m1) でストリームを送信した後、ストリーム m1 を初期化します。
// ソケットの会話が終了するまで残ります。
//手動で解放することはできません。そうでないと例外がトリガーされます
ビットマップで行う
始める
幅:= 画面の幅;
高さ:= 画面の高さ;
Canvas.CopyRect(canvas.cliprect,desk,desk.cliprect);
終わり;
jpg.Assign(bitmap); //画像をJPG形式に変換します。
jpg.SaveToStream(m1); //JPG画像をストリームに書き込みます
jpg.無料;
m1.位置:=0;
s1:=inttostr(m1.size);
Socket.sendtext(s1); //送信画像サイズ
終わり;
if s='okok' then //クライアントは画像を受信する準備ができています
始める
m1.位置:=0;
Socket.SendStream(m1); //JPG画像を送信
終わり;
終わり;
プロシージャ TForm1.FormCreate(送信者: TObject);
始める
ServerSocket1.open;
終わり;
終わり。