Вы находитесь на странице: 1из 7

1

// *****************************************************************************

2

//

File

: UServer.pas

3

//

Project : MicroServer.dpr

4

//

Easy example of TCP Server with indy component : TidTCPSever

5

//

6

//

see indy doc: http://www.indyproject.org/sockets/docs/index.en.aspx

7

//

8

//

9

// *****************************************************************************

10

unit UServer;

 

11

12

interface

 

13

14

uses

15

Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,

16

Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IdContext, IdComponent, Vcl.StdCtrls,

17

IdBaseComponent, IdCustomTCPServer, IdThreadSafe, IdTCPConnection, IdYarn, IdTCPServer, Vcl.ExtCtrls;

18

19

20

type

21

TFServer = class(TForm)

22

23

Title

: TLabel;

24

25

btn_start

: TButton;

26

btn_stop

: TButton;

27

btn_clear

: TButton;

28

29

clients_connected : TLabel;

30

Label1

: TLabel;

31

Panel1

: TPanel;

32

messagesLog

: TMemo;

33

34

procedure FormCreate(Sender: TObject);

35

procedure FormShow(Sender: TObject);

36

37

procedure btn_startClick(Sender: TObject);

38

procedure btn_stopClick(Sender: TObject);

39

procedure btn_clearClick(Sender: TObject);

40

41

procedure IdTCPServerConnect(AContext: TIdContext);

42

procedure IdTCPServerDisconnect(AContext: TIdContext);

43

procedure IdTCPServerExecute(AContext: TIdContext);

44

procedure IdTCPServerStatus(ASender: TObject; const AStatus: TIdStatus;

45

const AStatusText: string);

46

47

procedure ShowNumberOfClients(p_disconnected : Boolean=False);

48

49

procedure BroadcastMessage(p_message : string);

50

51

procedure Display(p_sender, p_message : string);

52

function GetNow():String;

53

54

55

private

56

{ Private declarations }

57

58

public

59

{ Public declarations }

60

61

end;

62

//

63

64

65

//

listening port

66

const GUEST_CLIENT_PORT = 20010;

67

68

var

69

FServer

: TFServer;

70

71

//

Id TCP Server

72

IdTCPServer : TIdTCPServer;

 

73

74

implementation

 

75

76

{$R *.dfm}

 

77

78

// *****************************************************************************

79

//

EVENT : onCreate()

80

//

ON FORM CREATE

81

// *****************************************************************************

82

procedure TFServer.FormCreate(Sender: TObject);

83

begin

84

85

//

create idTCPServer

86

IdTCPServer

:= TIdTCPServer.Create(self);

87

IdTCPServer.Active

:= False;

88

89

//

set properties

90

IdTCPServer.MaxConnections := 20;

 

91

92

//

etc

93

94

//

assign a new context class (if you need)

95

// IdTCPServer.ContextClass

:= TYourContext;

96

97

//

add some callback functions

 

98

IdTCPServer.OnConnect

:= IdTCPServerConnect;

99

IdTCPServer.OnDisconnect

:= IdTCPServerDisconnect;

100

IdTCPServer.OnExecute

:= IdTCPServerExecute;

101

IdTCPServer.OnStatus

:= IdTCPServerStatus;

102

//

etc

103

104

end;

105

//

106

107

108

// *****************************************************************************

109

//

EVENT : onShow()

110

//

ON FORM SHOW

111

// *****************************************************************************

112

procedure TFServer.FormShow(Sender: TObject);

113

begin

114

//

INITIALIZE:

115

116

//

clear message log

117

messagesLog.Lines.Clear;

 

118

119

//

zero to clients connected

 

120

clients_connected.Caption

:= inttostr(0);

121

122

//

set buttons

123

btn_start.enabled

:= True;

124

btn_stop.enabled

:= False;

125

end;

126

//

127

128

129

// *****************************************************************************

130

//

EVENT : btn_startClick()

131

//

CLICK ON START BUTTON

 

132

// *****************************************************************************

133

procedure TFServer.btn_startClick(Sender: TObject);

134

begin

135

//

START SERVER:

136

137

//

clear the Bindings property (

Socket Handles )

138

IdTCPServer.Bindings.Clear;

 

139

//

Bindings is a property of class: TIdSocketHandles;

140

141

//

add listening ports:

142

143

//

add a port for connections from guest clients.

144

IdTCPServer.Bindings.Add.Port := GUEST_CLIENT_PORT;

145

//

etc

146

147

148

//

ok, Active the Server!

149

IdTCPServer.Active

:= True;

150

151

//

disable start button

152

btn_start.enabled

:= False;

153

154

//

enable stop button

155

btn_stop.enabled

:= True;

156

157 //

message log

158

Display('SERVER', 'STARTED!');

 

159

160

end;

161

//

162

163

164

// *****************************************************************************

165

//

EVENT : btn_stopClick()

 

166

//

CLICK ON STOP BUTTON

167

// *****************************************************************************

168

procedure TFServer.btn_stopClick(Sender: TObject);

169

begin

170

171

//

before stopping the server

send 'good bye' to all clients connected

172

BroadcastMessage('Goodbye Client ');

173

174

//

stop server!

175

IdTCPServer.Active := False;

 

176

177

//

hide stop button

 

178

btn_stop.enabled

:= False;

179

180

//

show start button

 

181

btn_start.enabled := True;

182

183

//

message log

184

Display('SERVER', 'STOPPED!');

185

186

end;

187

//

188

189

190

// *****************************************************************************

191

//

EVENT : btn_clearClick()

192

//

CLICK ON CLEAR BUTTON

193

// *****************************************************************************

194

procedure TFServer.btn_clearClick(Sender: TObject);

195

begin

196

//

clear messages log

197

MessagesLog.Lines.Clear;

198

end;

199

//

200

201

//

202

//

203

//

204

205

// *****************************************************************************

206

//

EVENT : onConnect()

207

//

OCCURS ANY TIME A CLIENT IS CONNECTED

208

// *****************************************************************************

209

procedure TFServer.IdTCPServerConnect(AContext: TIdContext);

210

var

211

ip

: string;

212

port

: Integer;

213

peerIP

: string;

214

peerPort

: Integer;

215

216

nClients

: Integer;

217

218

msgToClient : string;

 

219

typeClient : string;

220

221

begin

222

//

OnConnect is a TIdServerThreadEvent property that represents the event

223

//

handler signalled when a new client connection is connected to the server.

224

225

//

Use OnConnect to perform actions for the client after it is connected

226

//

and prior to execution in the OnExecute event handler.

227

228

//

see indy doc:

 

229

// http://www.indyproject.org/sockets/docs/index.en.aspx

230

231

//

getting IP address and Port of Client that connected

232

ip

:= AContext.Binding.IP;

233

port

:= AContext.Binding.Port;

234

peerIP

:= AContext.Binding.PeerIP;

235

peerPort := AContext.Binding.PeerPort;

236

237

//

message log

238

Display('SERVER', 'Client Connected!');

+

'

+ '(PeerIP=' + PeerIP

239

240

Display('SERVER', 'Port=' + IntToStr(Port) '

241

+ ' - ' + 'PeerPort=' + IntToStr(PeerPort) + ')'

242

);

243

244

//

display the number of clients connected

245

ShowNumberOfClients();

 

246

247

//

CLIENT CONNECTED:

 

248

case Port of

249

GUEST_CLIENT_PORT

: begin

 

250

//

GUEST CLIENTS

251

typeClient := 'GUEST';

252

end;

253

//

254

end;

255

256

//

send the Welcome message to Client connected

257

msgToClient := 'Welcome ' + typeClient + ' ' + 'Client :)';

258

AContext.Connection.IOHandler.WriteLn( msgToClient );

259

260

end;

261

//

262

263

// *****************************************************************************

264

//

EVENT : onDisconnect()

 

265

//

OCCURS ANY TIME A CLIENT IS DISCONNECTED

266

// *****************************************************************************

267

procedure TFServer.IdTCPServerDisconnect(AContext: TIdContext);

268

var

269

ip

: string;

 

270

port

: Integer;

 

271

peerIP

: string;

 

272

peerPort

: Integer;

 

273

274

nClients

: Integer;

 

275

begin

276

277

//

getting IP address and Port of Client that connected

278

ip

:= AContext.Binding.IP;

279

port

:= AContext.Binding.Port;

280

peerIP

:= AContext.Binding.PeerIP;

281

peerPort := AContext.Binding.PeerPort;

282

283

//

message log

284

Display('SERVER', 'Client Disconnected! Peer=' + PeerIP + ':' + IntToStr(PeerPort));

285

286

//

display the number of clients connected

287

ShowNumberOfClients(true);

 

288

end;

289

//

290

291

292

// *****************************************************************************

293

//

EVENT : onExecute()

 

294

//

ON EXECUTE THREAD CLIENT

295

// *****************************************************************************

296

procedure TFServer.IdTCPServerExecute(AContext: TIdContext);

297

var

298

Port

: Integer;

299

PeerPort

: Integer;

 

300

PeerIP

: string;

301

302

msgFromClient : string;

 

303

msgToClient

: string;

304

begin

305

306

//

OnExecute is a TIdServerThreadEvents event handler used to execute

307

//

the task for a client connection to the server.

308

309

//

here you can check connection status and buffering before reading

310

//

messages from client

311

312

//

see doc:

313

//

AContext.Connection.IOHandler.InputBufferIsEmpty

314

//

AContext.Connection.IOHandler.CheckForDataOnSource(<milliseconds>);

315

//

(milliseconds to wait for the connection to become readable)

316

//

AContext.Connection.IOHandler.CheckForDisconnect;

317

318

//

received a message from the client

319

320

//

get message from client

321

msgFromClient := AContext.Connection.IOHandler.ReadLn;

322

323

//

getting IP address, Port and PeerPort from Client that connected

324

peerIP

:= AContext.Binding.PeerIP;

325

peerPort := AContext.Binding.PeerPort;

326

327

//

message log

328

Display('CLIENT', '(Peer=' + PeerIP + ':' + IntToStr(PeerPort) + ') ' +

msgFromClient);

 

329

//

330

331

//

process message from Client

332

333

//

334

335

//

send response to Client

336

337

AContext.Connection.IOHandler.WriteLn('

message sent from server :)');

338

339

end;

340

//

341

342

343

// *****************************************************************************

344

//

EVENT : onStatus()

 

345

//

ON STATUS CONNECTION

346

// *****************************************************************************

347

procedure TFServer.IdTCPServerStatus(ASender: TObject; const AStatus: TIdStatus;

348

const AStatusText: string);

349

begin

350

//

OnStatus is a TIdStatusEvent property that represents the event handler

351

//

triggered when the current connection state is changed

352

353

//

message log

354

Display('SERVER', AStatusText);

 

355

end;

356

//

357

358

359

// *****************************************************************************

360

//

FUNCTION : getNow()

 

361

//

GET MOW DATE TIME

362

// *****************************************************************************

363

function TFServer.getNow() : String;

364

begin

 

365

Result := FormatDateTime('yyyy-mm-dd hh:nn:ss', Now) + ': ';

366

end;

367

//

368

369

370

// *****************************************************************************

371

//

PROCEDURE : broadcastMessage()

372

//

BROADCAST A MESSAGE TO ALL CLIENTS CONNECTED

373

// *****************************************************************************

374

procedure TFServer.broadcastMessage(p_message : string);

375

var

376

tmpList

: TList;

377

contexClient : TidContext;

378

nClients

: Integer;

379

i

: integer;

380

begin

381

382

//

send a message to all clients connected

383

384

//

get context Locklist

385

tmpList := IdTCPServer.Contexts.LockList;

386

387

try

388

i := 0;

389

while ( i < tmpList.Count ) do begin

390

//

get context (thread of i-client)

391

contexClient := tmpList[i];

392

393

//

send message to client

394

contexClient.Connection.IOHandler.WriteLn(p_message);

395

i := i + 1;

396

end;

397

398

finally

399

//

unlock list of clients!

400

IdTCPServer.Contexts.UnlockList;

401

end;

402

end;

403

//

404

405

// *****************************************************************************

406

//

PROCEDURE : Display()

407

//

DISPLAY MESSAGE UPON SYSOUT

408

// *****************************************************************************

409

procedure TFServer.Display(p_sender : String; p_message : string);

410

begin

 

411

//

DISPLAY MESSAGE

412

TThread.Queue(nil, procedure

413

begin

414

MessagesLog.Lines.Add('[' + p_sender + '] - '

415

+ getNow() + ': ' + p_message);

416

end

417

);

418

419

//

see doc

420

//

TThread.Queue() causes the call specified by AMethod to

421

//

be asynchronously executed using the main thread, thereby avoiding

422

//

multi-thread conflicts.

423

end;

424

//

425

426

// *****************************************************************************

427

//

PROCEDURE : ShowNumberOfClients()

428

//

NUMBER OF CLIENTS CONNECTD

429

// *****************************************************************************

430

procedure TFServer.ShowNumberOfClients(p_disconnected : Boolean=False);

431

var

432

nClients : integer;

433

begin

 

434

435

try

436

//

get number of clients connected

437

nClients := IdTCPServer.Contexts.LockList.Count;

438

finally

439

IdTCPServer.Contexts.UnlockList;

440

end;

441

442

//

client disconnected?

443

if p_disconnected then dec(nClients);

444

445

//

display

446

TThread.Queue(nil, procedure

447

begin

448

clients_connected.Caption := IntToStr(nClients);

449

end

450

);

451

end;

452

//

453

454

455

end.