我把client的socket初始化內容寫在了message響應函數里面了,每次觸發消息的時候就把客戶端的socket置0了
服務器端代碼如下:
由于比較簡單,所以不貼注釋了,如果有什么不懂d地方,大家對著翻吧
unit Listener;
interface
uses
SysUtils, Controls, Forms, winsock, Classes, ComCtrls, StdCtrls;
const ASYNC_EVENT = $0400 + 1;
SO_CONDITIONAL_ACCEPT = $3002;
type
TCMSocketMessage = record //select 消息結構
Msg: Cardinal; //系統消息
Socket: TSocket; //產生消息的源socket 句柄
SelectEvent: Word; //select消息
SelectError: Word; //錯誤
Result: Longint;
end;
type
TMain = class(TForm)
SBar: TStatusBar;
Memo1: TMemo;
procedure FormDestroy(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
s: TSocket;
SClinent: TSocket;
procedure bindAddr;
procedure CMIncCount(var Msg: TCMSocketMessage); message ASYNC_EVENT;
procedure listenAddr;
{ Private declarations }
public
{ Public declarations }
end;
var
Main: TMain;
implementation
{$R *.dfm}
procedure TMain.FormDestroy(Sender: TObject);
begin
closeSocket(s);
WSACleanup();
end;
procedure TMain.FormCreate(Sender: TObject);
var
wsa: TWSaData;
flag: integer;
begin
SClinent := 0;
//SysUtils.BoolToStr()
flag := WSAStartup($0202, wsa); //加載winsock
if flag <> 0 then begin
SBar.Panels[2].Text := format('錯誤號:%d', [WSAGetLastError()]);
SBar.Panels[1].Text := 'Winsock庫加載失敗';
end;
bindAddr;
listenAddr;
end;
procedure TMain.bindAddr;
var
addr: TSockAddrIn;
flag: integer;
begin
s := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //服務器端的socket
addr.sin_port := htons(45531);
addr.sin_family := AF_INET;
addr.sin_addr.S_addr := INADDR_ANY; //inet_addr(pchar(host));
flag := bind(s, addr, sizeof(addr));
if flag = SOCKET_ERROR then begin
SBar.Panels[2].Text := format('錯誤號:%d', [WSAGetLastError()]);
SBar.Panels[1].Text := 'IP綁定錯誤';
end else begin
flag := WSAAsyncSelect(s, Handle, ASYNC_EVENT, FD_ACCEPT or FD_CONNECT or FD_CLOSE or FD_READ or FD_WRITE);
if flag = SOCKET_ERROR then begin
SBar.Panels[2].Text := format('錯誤號:%d', [WSAGetLastError()]);
SBar.Panels[1].Text := 'WSAAsyncSelect錯誤';
end;
end;
end;
procedure TMain.listenAddr;
var flag: integer;
begin
flag := listen(s, 10);
if flag = SOCKET_ERROR then begin
SBar.Panels[2].Text := format('錯誤號:%d', [WSAGetLastError()]);
SBar.Panels[1].Text := '監聽失敗';
end;
end;
procedure TMain.CMIncCount(var Msg: TCMSocketMessage);
var
addr: TSockAddrIn;
len: integer;
SendBuf: array[1..1024] of AnsiChar;
recvBuf: array[1..1024] of AnsiChar;
str: string;
OldOpenType {, NewOpenType}: integer;
begin
len := 0;
str := '';
case Msg.SelectEvent of
FD_READ: begin
len := sizeof(recvBuf);
ioctlsocket(SClinent, FIONREAD, Longint(len));
fillchar(recvBuf, sizeof(recvBuf), 0);
recv(SClinent, recvBuf, sizeof(recvBuf), 0);
Memo1.Lines.Add(string(recvBuf));
Memo1.Lines.Add('read');
if Memo1.Lines.Count > 10 then
memo1.Clear;
sleep(10);
fillchar(SendBuf, sizeof(SendBuf), 0);
Strcopy(@SendBuf, pansichar('OK'));
Send(SClinent, sendbuf, sizeof(sendbuf), 0);
end;
FD_WRITE: begin
Memo1.Lines.Add('write');
end;
FD_ACCEPT: begin
len := sizeof(OldOpenType);
if getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@OldOpenType), len) = 0 then begin
try
len := sizeof(addr);
SClinent := accept(s, @addr, @len);
if SClinent = INVALID_SOCKET then begin
Memo1.Lines.Add('無效的socket:' + inttostr(SClinent));
end;
Memo1.Lines.Add('accept');
finally
len := sizeof(OldOpenType);
setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, PChar(@OldOpenType), len);
end;
end;
WSAAsyncSelect(SClinent, handle, ASYNC_EVENT, $33);
end;
FD_CONNECT: begin
Memo1.Lines.Add('connect');
end;
FD_CLOSE: begin
Memo1.Lines.Add('close');
end;
end;
end;
end.
//由于服務器端沒有緩存機制,所以多個client連接的時候,第二個client的socket會覆蓋前一個的,大家看情況改改就行了,網絡上大把代碼都是用控件或者其他封裝好d類來寫d,所以資料郁悶死了.
客戶端代碼:
program Client;
{$APPTYPE CONSOLE}
uses
SysUtils,
windows,
winsock;
var
addr: TSockAddrIn;
wsa: TWSaData;
flag: integer;
s: TSocket;
Host: string;
Port: Word;
BufSend: array[1..1024] of Ansichar; //中間信息
BufRev: array[1..1024] of Ansichar;
i: Integer;
begin
{ TODO -oUser -cConsole Main : Insert code here }
Host := '127.0.0.1';
port := 45531;
flag := WSAStartup($0202, wsa); //加載winsock
if flag <> 0 then begin
Writeln(format('錯誤號:%d', [WSAGetLastError()]));
Writeln('Winsock庫加載失敗');
end else begin
Writeln('Winsock庫加載成功')
end;
//s := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //服務器端的socket
s := socket(PF_INET, SOCK_STREAM, 0);
FillChar(addr, sizeof(addr), 0); //初始化地址空間
addr.sin_port := htons(port);
addr.sin_family := AF_INET;
addr.sin_addr.S_addr := {INADDR_ANY; } inet_addr(pchar(host));
if connect(s, addr, sizeof(addr)) = 0 then begin
Writeln('主機:' + Host + ' 連接成功')
end else begin
Writeln('主機:' + Host + ' 連接失敗');
end;
FillChar(BufSend, 1024, 0);
StrPCopy(@BufSend, '測試信息包');
for i := 0 to 100 do begin
Writeln(inttostr(s));
if Send(s, Bufsend, Length(BufSend), 0) <> SOCKET_ERROR then begin
Writeln('消息已發送');
sleep(500);
FillChar(BufRev, 1024, 0);
//strcopy(bufsend,pansichar('a'))
if recv(s, BufRev, Length(BufSend), 0) <> SOCKET_ERROR then begin
writeln('接收到的信息:' + trim(string(BufRev)));
end else begin
Writeln('接收消息失敗!')
end;
end else begin
Writeln('消息發送失敗')
end;
end;
if closeSocket(s) = 0 then begin
Writeln('已經關閉socket')
end else begin
Writeln('關閉socket 出錯')
end;
WSACleanup();
Readln;
end.