学习笔记: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.

原文地址:https://www.cnblogs.com/wangorg/p/2031812.html