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博客,转载请标明出处: