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

posted @ 2010-09-28 23:07  tc310  阅读(355)  评论(0编辑  收藏  举报