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.
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