博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WinSock学习笔记3:Select模型
阅读量:5933 次
发布时间:2019-06-19

本文共 2730 字,大约阅读时间需要 9 分钟。

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

你可能感兴趣的文章
jCasbin:支持MAC、RBAC、ABAC多种模型的Java权限管理框架
查看>>
多线程基础必要知识点!看了学习多线程事半功倍
查看>>
laravel 内容理解和摘要
查看>>
订阅号页面偷取微信用户信息(unionId),-_-
查看>>
PHP SPL 笔记
查看>>
HTML、CSS笔记
查看>>
让前端攻城师独立于后端进行开发: Mock.js
查看>>
golang通用连接池的实现
查看>>
zookeeper和etcd有状态服务部署实践
查看>>
从koa-session中间件源码学习cookie与session
查看>>
事件处理---事件等级模型,捕获,冒泡,默认事件。
查看>>
ERP物理机迁移至阿里云实践
查看>>
30-seconds-code——string
查看>>
vue入坑笔记(持续更新)
查看>>
webpack选择性编译DefinePlugin(打包自动剔除测试数据)
查看>>
Sequelize 中文文档 v4 - Transactions - 事务
查看>>
SpringCloud(第 006 篇)电影微服务,使用 Ribbon 在客户端进行负载均衡
查看>>
深入理解Memcache
查看>>
SpringCloud(第 041 篇)链接Mysql数据库,通过JdbcTemplate编写数据库访问
查看>>
CSS 属性赋值
查看>>