WinSock学习笔记3:Select模型

 

unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, WinSock, ExtCtrls; type TWorkThread = class(TThread) private FClientSocket: TSocket; FMemo: TMemo; FBuff: array [0..10] of Char; procedure ShowRecv; protected procedure Execute;override; public constructor Create(ClientSocket: TSocket; Memo: TMemo); end; TForm1 = class(TForm) Memo1: TMemo; Button1: TButton; Timer1: TTimer; procedure Button1Click(Sender: TObject); procedure Timer1Timer(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; ServerSocket: TSocket; ClientSocket: TSocket; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var WSData: WSAData; LocalAddr: TSockAddrIn; SocketMode: Integer; begin //初始化Winsock WSAStartUp($202, WSData); //创建套接字 ServerSocket:= Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //设置LocalAddr的参数 LocalAddr.sin_family:= AF_INET; //IPV4族 LocalAddr.sin_addr.S_addr:= Inet_addr('127.0.0.1');//点分字符串格式的IP地址转换为互联网格式 LocalAddr.sin_port:= Htons(1077); //Host To Net Short,主机字节顺序转为网络字节顺序 //绑定本机IP地址、端口,绑定之前先设置好LocalAddr的参数 Bind(ServerSocket, LocalAddr, SizeOf(LocalAddr)); //设置WinSock I/O模式 SocketMode:= 1; IoCtlSocket(ServerSocket, FIONBIO, SocketMode); //开始监听,最多同时监听5个连接 Listen(ServerSocket, 5); Timer1.Enabled:= True; end; { TWorkThread } constructor TWorkThread.Create(ClientSocket: TSocket; Memo: TMemo); begin inherited Create(False); FClientSocket:= ClientSocket; FMemo:= Memo; end; procedure TWorkThread.Execute; var FDSet: TFDSET; begin inherited; FreeOnTerminate:= True; while not Terminated do begin FD_Zero(FDSet); //初始化FDSet FD_SET(FClientSocket, FDSet); //将FClientSocket加入FDSet if Select(0, @FDSet, nil, nil, nil) > 0 then //测试FDSet中是否有可读的连接 begin if Recv(FClientSocket, FBuff, SizeOf(FBuff), 0) > 0 then //如果收到消息就显示出来 Synchronize(ShowRecv) else Break; end; end; end; procedure TWorkThread.ShowRecv; begin FMemo.Lines.Add(FBuff); end; procedure TForm1.Timer1Timer(Sender: TObject); begin ClientSocket:= Accept(ServerSocket, nil, nil); if ClientSocket <> INVALID_SOCKET then TWorkThread.Create(ClientSocket, Memo1); end; end.

 

1.使用Select模型,要定义一个FDSet结构,将客户端Socket加入该结构,用Select函数轮询测试该Socket的读写状态。FDSet结构:

    typedef struct fd_set {
      u_int fd_count;                                      
      SOCKET fd_array[FD_SETSIZE];           
    } fd_set;

 

2.操作FDSet结构有4个预定义的宏:

       FD_CLR( s , * set )
Removes the descriptor s from set.
       FD_ISSET( s , * set )
Nonzero if s is a member of the set. Otherwise, zero.
       FD_SET( s , * set )
Adds descriptor s to set.
       FD_ZERO(* set )
Initializes the set to the null set.

3.上面的代码为了方便,用了一个Timer来Accept,然后为每一个连接进来的Socket创建线程,在线程中用Select测试是否可读,为使代码简单,没有处理异常的代码。

你可能感兴趣的:(WinSock学习笔记3:Select模型)