お知らせ

電子会議

ライブラリ

パレット

Delphi FAQ検索

Delphi FAQ一覧

サンプル蔵





FDelphi FAQ
16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル

"RE:TServerSocketでブロッキング通信"

この発言は
#00986 KeY さんのTServerSocketでブロッキング通信
に対するコメントです

みなさんこんにちは、KeYです。 TServerSocketでstThreadBlockingを使用するときのサンプルです。 WindowsNTで動かなかったのを修正しました。 WinSock.ShutDownを明示的に行ってみたらうまくいきました。 あと、リクエストの読みとり方があんまりだったので修正しました。 アップロード前にホームページのテストをしてみたりするのにどうぞ。 //----Unit1.pasここから unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ScktComp, WinSock; type TForm1 = class(TForm) ServerSocket1: TServerSocket; procedure ServerSocket1GetThread(Sender: TObject; ClientSocket: TServerClientWinSocket; var SocketThread: TServerClientThread); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private 宣言 } public { Public 宣言 } end; TTinyHttpdThread = class(TServerClientThread) private { Private 宣言 } protected procedure ClientExecute; override; end; const RootDir='c:\Delphi4\Httpd\Root'; //ドキュメントルート PortNo=8080; //ポート番号 DefaultDoc='index.html'; //デフォルトの文書名 Response403='HTTP/1.0 403 Forbidden'#13#10+ 'Content-Type: text/plain'#13#10#13#10'Error 403 Forbidden'; Response404='HTTP/1.0 404 Not Found'#13#10+ 'Content-Type: text/plain'#13#10#13#10'Error 404 Not Found'; var Form1: TForm1; implementation {$R *.DFM} var ContentTypes: TStrings; procedure TForm1.FormCreate(Sender: TObject); begin ServerSocket1.Port:=PortNo; ServerSocket1.ServerType:=stThreadBlocking; ServerSocket1.Active:=True; end; procedure TForm1.FormDestroy(Sender: TObject); begin if ServerSocket1.Active then begin ServerSocket1.Active:=False; end; end; procedure TForm1.ServerSocket1GetThread(Sender: TObject; ClientSocket: TServerClientWinSocket; var SocketThread: TServerClientThread); begin SocketThread:=TTinyHttpdThread.Create(False, ClientSocket); end; { TTiniHttpdThread } procedure TTinyHttpdThread.ClientExecute; var Stream: TWinSocketStream; Buffer: array[0..4095] of Char; GetSize: Integer; HttpReqStr: TStrings; HttpReqHeaderFlg: Boolean; //まだHTTPヘッダの中かどうかのフラグ s: string; i: Integer; SendFile: TFileStream; SendFileExt: string; SendHeader: string; ContentType: string; begin HttpReqStr:=TStringList.Create; try //このループはお決まりのもの ただしこのプログラムでは機能しない while (not Terminated) and ClientSocket.Connected do begin try //ソケットストリームの作成 Stream:=TWinSocketStream.Create(ClientSocket, 60000); try //受信可能状態になるのを待つ if Stream.WaitForData(60000) then begin //リクエストを読んでTStringsに保存 HttpReqHeaderFlg:=True; HttpReqStr.Clear; HttpReqStr.Add(''); GetSize:=Stream.Read(Buffer, sizeof(Buffer)); if GetSize=0 then Exit; while HttpReqHeaderFlg do begin for i:=0 to GetSize-1 do begin case Buffer[i] of #13: if HttpReqStr.Strings[HttpReqStr.Count-1]='' then begin //空行だったらヘッダ部の終わり // 本当なら、POSTメソッドの場合にはその引数が // この後に続く。この例ではGETメソッドしか見て // ないのでここで終わり HttpReqHeaderFlg:=False; break; //for i:=0〜 end else HttpReqStr.Add(''); #10: ; //ここは手抜き。#13#10がセットで現れる //ことを期待して、#10を無視している else HttpReqStr.Strings[HttpReqStr.Count-1]:= HttpReqStr.Strings[HttpReqStr.Count-1]+Buffer[i]; end; end; if HttpReqHeaderFlg then begin GetSize:=Stream.Read(Buffer, sizeof(Buffer)); if GetSize=0 then Exit; end; end; //GETメソッドか? if CompareText( Copy(HttpReqStr.Strings[0], 1, 4),'GET ')=0 then begin //'GET 'を削除 s:=Copy(HttpReqStr.Strings[0], 5, Length(HttpReqStr.Strings[0])); s:=Trim(s); //ディレクトリ部分だけ抜き出す if Pos(' ', s)>0 then s:=Copy(s, 1, Pos(' ', s)-1); //'/'を'\'に変更 s:=StringReplace(s, '/', '\', [rfReplaceAll]); //ルートディレクトリを付ける s:=rootdir+s; //最後がフォルダならデフォルトファイルを追加 if s[Length(s)]='\' then s:=s+DefaultDoc; //ファイルをオープン // CGI引数付きのGETメソッドはここで失敗する // また引数なしのCGIプログラムはそのまま // ファイルを渡してしまうので注意 try SendFile:=TFileStream.Create( s, fmOpenRead or fmShareDenyWrite ); except //失敗したら404のエラー SendFile:=nil; s:=Response404; Stream.Write(s[1], Length(s)); end; if Assigned(SendFile) then begin try //拡張子を取得 SendFileExt:=ExtractFileExt(s); //'.'を取り除く Delete(SendFileExt,1,1); //Content-Typeを決定 ContentType:=ContentTypes.Values[s]; if s='' then ContentType:='application/octet-stream'; //最低限のヘッダを送信 SendHeader:='HTTP/1.0 200 '#13#10+ 'Content-Type: '+ContentType+#13#10#13#10; Stream.Write(SendHeader[1], Length(SendHeader)); //ファイルを送信 GetSize:=SendFile.Read(Buffer, sizeof(Buffer)); while GetSize>0 do begin Stream.Write(Buffer, GetSize); GetSize:=SendFile.Read(Buffer, sizeof(Buffer)); end; finally SendFile.Free; end; end; end else begin //GETメソッド以外には対応していない s:=Response403; Stream.Write(s[1], Length(s)); end; end; finally //ソケットストリームを破棄 Stream.Free; //ClientSocket.Closeの中でshutdownしていないためか //このプログラムをNTで動かすとブラウザがエラーを出す //明示的にshutdownしておくと回避できるようだ WinSock.shutdown(ClientSocket.SocketHandle, 2); end; Exit; except HandleException; end; end; finally HttpReqStr.Free; end; end; initialization ContentTypes:=TStringList.Create; ContentTypes.Add('HTML=text/html'); ContentTypes.Add('HTM=text/html'); ContentTypes.Add('JPEG=image/jpeg'); ContentTypes.Add('JPG=image/jpeg'); ContentTypes.Add('GIF=image/gif'); finalization ContentTypes.Free; end. //----Unit1.pasここまで 99/12/8(Wed) 09:21pm VEJ04660 KeY Original document by KeY 氏 ID:(VEJ04660)



ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。

Copyright 1996-2002 Delphi Users' Forum