WinSock学习笔记3:Select模型

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测试是否可读,为使代码简单,没有处理异常的代码。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/dropme/archive/2009/09/09/4534748.aspx

你可能感兴趣的:(select)