学习笔记:delphi实现网络通信之select模型

说明:所有的winsock的定义用的是jwawinsock2。(整个包的下载:http://blog.delphi-jedi.net/home/)

主要函数:select

目的:允许那些想要避免在套接字调用上阻塞的应用程序有能力管理多个套接字。

函数定义:select(nfds:integer;readfds:Pfd_set;writefds:Pfd_set;exceptfds:Pfd_set;timeout:Ptimeval)

套接集合:FD_SET结构

PFD_SET=^Fd_set

Fd_set=record

fd_count:integer;

fd_array:array[0..FD_SETSIZE-1] of Tsocket;

end;{FD_SETSIZE系统默认为64.也就是系统默认管理64个套接字。实际可以定义到1000。}

关于FD_SET集合操作函数。

FD_ZERO(SET:PFD_SET) 初始化set为空集合。集合在使用前应该总是清空。

FD_CLR(s:TSOCKET;set:PFD_SET) 从set移除套接字。

FD_ISSETs(S:TSOCKET;SET:PFD_SET) 检查s是不是set的成员,如果是返回TRUE。

FD_SET(S:TSOCKET;set:PFD_SET)添加套接字到集合。

delphi代码:

program Proserver;

//控制台程序。

{$APPTYPE CONSOLE}

uses

JwaWinsock2,Windows,SysUtils;

var

nPort:UINT;

sListen,sNew:TSocket;

socket_in,addrRemote:sockaddr_in;

fdSocket,fdRead:fd_set;

i,nAddrLen:integer;

szText:array[0..255] of AnsiChar;

procedure initsock;

var

v_wsadata:WSAData;

sockversion:Cardinal;

begin

sockversion:=MAKEWORD(2,2);

try

if WSAStartup(sockversion,v_wsadata)<>0 then

Exit;

except

Exit;

end;

end;

procedure cleansock;

begin

WSACleanup();

end;

begin

initsock;

nport:=4567;

sListen:=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

socket_in.sin_family:=AF_INET;

socket_in.sin_port:=htons(nPort);

socket_in.sin_addr.S_addr:=INADDR_ANY;

//进行SOCKET绑定到本地机器

if bind(sListen,psockaddr(@socket_in),SizeOf(socket_in))=socket_error then

begin

writeln('Failed bind()');

Exit;

end

else

begin

Writeln('SOCKET绑定成功。');

end;

//进入监听模式

Writeln('程序进入监听状态......');

listen(sListen,5);

//select模型处理过程

//1、初始化一个套接字集合fdsocket,添加监听套接字句柄到这个集合。

FD_ZERO(fdSocket);

_FD_SET(sListen,fdSocket);

//进行等待状态中。。。。。。

Writeln('进入无限循环状态。。。。。');

while True do

begin

// 2、将FDSOCKET集合的一个拷贝FDREAD传递给SELECT函数。

fdRead:=fdSocket;

if select(0,@fdread,nil,nil,nil)>0 then

begin

for i:=0 to fdSocket.fd_count-1 do

begin

if FD_ISSET(fdSocket.fd_array[i],fdRead) then

begin

if fdSocket.fd_array[i]=sListen then

begin

if fdSocket.fd_count<FD_SETSIZE then

begin

nAddrLen:=SizeOf(addrRemote);

sNew:=accept(sListen,psockaddr(@addrRemote),@nAddrlen);

_FD_SET(sNew,fdSocket);

Writeln('接收到连接:'+strpas(inet_ntoa(addrRemote.sin_addr)));

end

else

begin

Writeln('连接太多,超出系统要求。');

Continue;

end;

end

else

begin

if recv(fdSocket.fd_array[i],szText,SizeOf(szText),0)>0 then

begin

Writeln('接收的数据是:'+strpas(sztext));

end

else

begin

closesocket(fdSocket.fd_array[i]);

FD_CLR(fdSocket.fd_array[i],fdSocket);

Writeln('当前连接已判断。');

end;

end;

end;

end;

end

else

begin

Writeln('Failed select().');

Break;

end;

end;

cleansock;

end.