我认为这段程序不错,可惜调试通不过,谁可以帮我调试一下这段程序?
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,StdCtrls, Winsock2, Global, SyncObjs;
type
TForm1 = class(TForm)
btnStartup: TButton;
btnCleanup: TButton;
Edit: TEdit;
btnClose: TButton;
cmbuserid: TComboBox;
Label1: TLabel;
Memo: TMemo;
Button1: TButton;
procedure btnStartupClick(Sender: TObject);
procedure btnCloseClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TServerThread = class(TThread)
public
procedure execute; override;
end;
var
Form1: TForm1;
EventTotal: DWord;
SocketArray: array [0..wsa_maximum_wait_events-1] of TSocket;
EventArray: array [0..wsa_maximum_wait_events-1] of WSAEvent;
NewEvent: TWSAEvent;
NetWorkEvents: PWSANetWorkEvents;
AcceptSocket, ListenSocket: TSocket;
buf: TBuf;
implementation
{$R *.dfm}
procedure TForm1.btnStartupClick(Sender: TObject);
var
wsaData: TWSAData;
ServerAddr: TSockAddrIn;
begin
EventTotal := 0;
Memo.Lines.add('Startup...');
WSAStartup(MakeWord(2,2), wsaData); //启动Winsock
Memo.Lines.Add('socket...');
ListenSocket := socket(AF_INET, Sock_Stream, IPProto_TCP); //建立监听socket
Memo.Lines.Add('bind...');
ServerAddr.sin_family := AF_INET;
ServerAddr.sin_port := htons(port);
ServerAddr.sin_addr.S_addr := htonl(INADDR_ANY);
bind(ListenSocket, @ServerAddr, SizeOf(ServerAddr); //绑定
NewEvent := WSACreateEvent(); //建立监听套接字事件
//选择要响应的事件消息(开始只响应接受消息,read和write消息在响应accept之后再select)
WSAEventSelect(ListenSocket, NewEvent, fd_accept or fd_close);
Memo.Lines.Add('listen...');
listen(ListenSocket, 5);
SocketArray[EventTotal] := ListenSocket; //关联监听,以便响应事件
EventArray[EventTotal] := NewEvent;
inc(EventTotal);
new(NetWorkEvents);
TServerThread.create(false);
end;
procedure TForm1.btnCloseClick(Sender: TObject);
begin
close;
end;
{ TServerThread }
procedure TServerThread.execute;
var
index, i: DWord;
ClientAddr: PSockAddrIn;
AddrLen: PInteger;
begin
new(ClientAddr);
new(AddrLen);
while not Terminated do
begin
//等候所有套接字上的网络事件。
index := WSAWaitForMultipleEvents(EventTotal, @EventArray, false, wsa_infinite, false);
dec(index, wsa_wait_event_0);
//遍历所有事件,查看被传信的事件是否多于一个
for i := index to EventTotal - 1 do
begin
index := WSAWaitForMultipleEvents(1, @EventArray, true, 1000, false);
if (index = wsa_wait_failed) or (index = wsa_wait_timeout) then
continue
else
begin
index := i;
//枚举发生的事件
WSAEnumNetWorkEvents(SocketArray[index], EventArray[index], NetWorkEvents);
//检查fd_accept消息
if NetworkEvents.lNetworkEvents = fd_accept then
begin
if NetworkEvents.iErrorCode[fd_accept_bit] <> 0 then //iErrorCode的错误代码在帮助中详细描述
begin
MainForm.memo.Lines.Add(format('fd_accept failed with error %d', [NetworkEvents.iErrorCode[fd_accept_bit]]));
break;
end;
//接受一个新连接,并将它添加到套接字及事件列表中
//注意:有时候accept会返回一个很大的数值(正常数值应该是从140左右开始的),
//但系统并不报错,而实际上返回AcceptSocket是无效的socket
AcceptSocket := Accept(SocketArray[index], ClientAddr^, AddrLen^);
//由于WSAWaitForMultipleEvents函数最多只能处理64个事件对象,故关闭接受套接字
if EventTotal > wsa_maximum_wait_events then
begin
MainForm.memo.Lines.Add('Too many connections');
CloseSocket(AcceptSocket);
break;
end;
NewEvent := WSACreateEvent(); //建立接收和发送套接字事件对象
//为刚才接受建立的Socket选择要响应的事件
WsaEventSelect(AcceptSocket, NewEvent, fd_read or fd_write or fd_close);
//把接受的socket存到数组中
EventArray[EventTotal] := NewEvent;
SocketArray[EventTotal] := AcceptSocket;
inc(Eventtotal);
MainForm.memo.Lines.Add(format('SocketHandle %d connected', [AcceptSocket]));
end;
//处理fd_read通知
if NetworkEvents.lNetworkEvents = fd_read then
begin
if NetworkEvents.iErrorCode[fd_read_bit] <> 0 then
begin
MainForm.memo.Lines.Add(format('fd_read failed with error %d', [NetworkEvents.iErrorCode[fd_read_bit]]));
break;
end;
if recv(SocketArray[index - wsa_wait_event_0], buf, bufsize, 0) = socket_error then //从套接字读入数据
raise exception.Create(IntToStr(GetLastError))
else
begin
MainForm.Memo.Lines.Add('[收到消息]' + buf.Msg);
if Send(SocketArray[buf.DestID + 1], buf, bufsize, 0) = socket_error then //转发
raise exception.Create(IntToStr(GetLastError))
else
MainForm.Memo.Lines.Add('[转发消息]' + buf.Msg);
end;
end;
if NetworkEvents.lNetworkEvents = fd_write then
begin
if NetworkEvents.iErrorCode[fd_write_bit] <> 0 then
begin
MainForm.memo.Lines.Add(format('fd_write failed with error %d', [NetworkEvents.iErrorCode[fd_write_bit]]));
break;
end;
buf.DestID := 0;
buf.Msg := 'Hello!Welcome to Server!';
buf.MsgType := stMsg;
buf.SourceID := 0;
send(SocketArray[index - wsa_wait_event_0], buf, bufsize, 0);
end;
//处理关闭事件
if NetworkEvents.lNetworkEvents = fd_close then
begin
if NetworkEvents.iErrorCode[fd_close_bit] <> 0 then
begin
MainForm.memo.Lines.Add(format('fd_close failed with error %d', [NetworkEvents.iErrorCode[fd_close_bit]]));
break;
end;
CloseSocket(SocketArray[index]);
end;
end;
end; //for
end; //while
dispose(ClientAddr);
dispose(AddrLen);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
buf: TBuf;
begin
if cmbUserID.ItemIndex = -1 then
cmbUserID.ItemIndex := 0;
if SocketArray[cmbUserID.ItemIndex] = 0 then
memo.Lines.Add(IntToStr(cmbUserID.ItemIndex) + ' is nil');
buf.DestID := 0;
buf.Msg := edit.Text;
buf.MsgType := stMsg;
buf.SourceID := -1;
if Send(SocketArray[cmbUserID.ItemIndex + 1], buf, bufsize, 0) = socket_error then
raise exception.Create(IntToStr(GetLastError))
else
memo.Lines.Add('[发送到' + IntToStr(cmbUserID.ItemIndex) + ']' + edit.Text);
end;
end.