[BlueLeaf1336]>
PROGRAM>
WEBサーバを作ろう-003
2003/08/10:作成
C/C++300の技
http://www.asahi-net.or.jp/~nk2w-ishr/
第3話。第1話はWEBサーバを作ろう-001。第2話はWEBサーバを作ろう-002。
第2話までテストコードを書いてきましたがこんなに短いくせにジョジョに嫌な感じになってきたので整理しておきます。
といっても、Winsock.pasの関数を呼ぶためラッパー関数をくくりだしておくだけですが。
20030810iWinSock.zip(3,177bytes):ソース
unit iWinSock;
interface
uses
Windows, SysUtils, Classes, WinSock;
function socket(): TSocket;
procedure closesocket(s: TSocket);
function MakeSockAddr(APort: integer; IPorName: string): TSockAddr;
procedure connect(s: TSocket; var name: TSockaddr);
procedure send(s: TSocket; stream: TStream); overload;
procedure send(s: TSocket; command: string); overload;
procedure send(s: TSocket; strings: TStrings); overload;
procedure recv(s: TSocket; stream: TStream); overload;
procedure recv(s: TSocket; strings: TStrings); overload;
function recv(s: TSocket): string; overload;
function recvonce(s: TSocket): string;
procedure bind(s: TSocket; var name: TSockaddr);
procedure listen(s: TSocket);
function accept(s: TSocket; clientname: TSockaddr): TSocket;
var
MaxSocketCount: integer = 0;
implementation
procedure RaiseError(AFuncName: string);
begin
raise Exception.CreateFmt('%s(iWinSock.pas):%s', [AFuncName, SysErrorMessage(WSAGetLastError)]);
end;
function WSAStartup(): integer;
const
VERSION: WORD = $0101;
var
WSAData: TWSAData;
begin
if (Winsock.WSAStartup(VERSION, WSAData) = 0) and (WSAData.wVersion = VERSION) then
begin
Result := WSAData.iMaxSockets;
end else
begin
Result := 0;
RaiseError('WSAStartup');
end;
end;
procedure WSACleanup();
begin
if Winsock.WSACleanup <> 0 then RaiseError('WSACleanup');
end;
type
PPChar = ^PChar;
function HostAliases(HostEntry: PHostEnt): string;
var
ppc: PPChar;
begin
Result := '';
try
ppc := PPChar(HostEntry^.h_aliases);
while Assigned(ppc^) do
begin
Result := Result + ',' + ppc^;
Inc(ppc);
end;
Result := Copy(Result, 2, Length(Result));
except
RaiseError('HostEntry^.h_aliases');
end;
end;
function HostAddressList(HostEntry: PHostEnt): string;
var
ppc: PPChar;
begin
Result := '';
try
ppc := PPChar(HostEntry^.h_addr_list);
while Assigned(ppc^) do
begin
Result := Result + ',' + inet_ntoa(PInAddr(ppc^)^);
Inc(ppc);
end;
Result := Copy(Result, 2, MaxInt);
except
RaiseError('HostEntry^.h_addr_list');
end;
end;
function gethostby(IPorName: string): PHostEnt;
var
ip : u_long;
begin
ip := inet_addr(PChar(IPorName));
if ip = INADDR_NONE then
begin
Result := Winsock.gethostbyname(PChar(IPorName));
end else
begin
Result := Winsock.gethostbyaddr(@ip, 4, AF_INET);
end;
if not Assigned(Result) then RaiseError('gethostby****');
end;
function InetAddress(IPorName: string): integer;
var
HostEntry: PHostEnt;
begin
HostEntry := gethostby(IPorName);
Result := inet_addr(inet_ntoa(PInAddr(HostEntry^.h_addr_list^)^));
end;
function socket(): TSocket;
begin
Result := Winsock.socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if Result = INVALID_SOCKET then RaiseError('socket');
end;
procedure closesocket(s: TSocket);
begin
if Winsock.closesocket(s) = SOCKET_ERROR then RaiseError('closesocket');
end;
function MakeSockAddr(APort: integer; IPorName: string): TSockAddr;
begin
FillChar(Result, SizeOf(TSockAddr), #0);
Result.sin_family := AF_INET;
Result.sin_port := htons(APort);
if IPorName <> '' then
Result.sin_addr.S_addr := InetAddress(IPorName)
else
Result.sin_addr.S_addr := INADDR_ANY
;
end;
procedure connect(s: TSocket; var name: TSockaddr);
begin
if Winsock.connect(s, name, sizeof(name)) = SOCKET_ERROR then RaiseError('connect');
end;
procedure send(s: TSocket; stream: TStream);
var
senddat: string;
sendlen, sentlen: integer;
begin
stream.Position := 0;
while True do
begin
senddat := '';
SetLength(senddat, stream.Size);
sendlen := stream.Read(senddat[1], stream.Size);
sentlen := Winsock.send(s, senddat[1], sendlen, 0);
if sentlen = SOCKET_ERROR then
begin
RaiseError('send');
end else
if sentlen < sendlen then
begin
stream.Seek(sendlen - sentlen, soFromCurrent);
end else
begin
Break;
end;
end;
end;
procedure send(s: TSocket; command: string);
var
stream: TStream;
begin
stream := TMemoryStream.Create;
try
stream.Write(command[1], Length(command));
send(s, stream);
finally
stream.Free;
end;
end;
procedure send(s: TSocket; strings: TStrings);
var
stream: TStream;
begin
stream := TMemoryStream.Create;
try
strings.SaveToStream(stream);
send(s, stream);
finally
stream.Free;
end;
end;
procedure recv(s: TSocket; stream: TStream);
var
recvdat: string;
recvlen: integer;
begin
while True do
begin
recvdat := '';
SetLength(recvdat, 8 * 1024);
recvlen := Winsock.recv(s, recvdat[1], Length(recvdat), 0);
if recvlen = SOCKET_ERROR then
begin
RaiseError('recv');
end else
if recvlen = 0 then
begin
Break;
end else
begin
stream.Write(recvdat[1], recvlen);
end;
end;
stream.Position := 0;
end;
procedure recv(s: TSocket; strings: TStrings);
var
stream: TStream;
begin
stream := TMemoryStream.Create;
try
recv(s, stream);
strings.LoadFromStream(stream);
finally
stream.Free;
end;
end;
function recv(s: TSocket): string;
var
stream: TStream;
res: integer;
begin
stream := TMemoryStream.Create;
try
recv(s, stream);
SetLength(Result, stream.Size);
res := stream.Read(Result[1], Length(Result));
SetLength(Result, res);
finally
stream.Free;
end;
end;
function recvonce(s: TSocket): string;
var
recvlen: integer;
begin
Result := '';
SetLength(Result, 8 * 1024);
recvlen := Winsock.recv(s, Result[1], Length(Result), 0);
if recvlen = SOCKET_ERROR then RaiseError('recv');
SetLength(Result, recvlen);
end;
procedure bind(s: TSocket; var name: TSockaddr);
begin
if Winsock.bind(s, name, sizeof(name)) = SOCKET_ERROR then RaiseError('bind');
end;
procedure listen(s: TSocket);
begin
if Winsock.listen(s, SOMAXCONN) = SOCKET_ERROR then RaiseError('listen');
end;
function accept(s: TSocket; clientname: TSockaddr): TSocket;
var
caddrlen: integer;
begin
caddrlen := SizeOf(clientname);
FillChar(clientname, SizeOf(TSockAddr), #0);
Result := Winsock.accept(s, @clientname, @caddrlen);
if Result = INVALID_SOCKET then RaiseError('accept');
end;
initialization
try
MaxSocketCount := WSAStartUp();
except
;
end;
finalization
try
WSACleanup();
except
;
end;
end.