没有合适的资源?快使用搜索试试~ 我知道了~
Winsocket入门教程二:非阻塞式服务器和客户端程序(TCP).doc
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 96 浏览量
2022-07-07
04:06:58
上传
评论
收藏 152KB DOC 举报
温馨提示
试读
17页
Winsocket入门教程二:非阻塞式服务器和客户端程序(TCP)HYPERLINK"JavaScript:d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(saveit=window.open('http://wz.csdn.net/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.locatio
资源推荐
资源详情
资源评论
Winsocket 入门教程二:非阻塞式服务器和客户端程序(TCP) 收藏
上次为大家介绍了阻塞式多线程服务端程序和阻塞式客户端程序的设计方法,但是在
上文的最后也提到过,服务器程序会因为建立连接和关闭连接而频繁的创建和关闭线程会产
生大量的内存碎片,从而导致服务端程序不能保证长时间的稳定运行。因此我在这里为大家
介绍另外一种建立服务器和客户端程序的方法,即建立非阻塞式的服务器和客户端程序。
那什么是非阻塞呢?非阻塞是相对于阻塞而言,阻塞指的是在进行一个操作的时候,
如服务器接收客户端的连接(accept),服务器或者客户端读写数据(read、write),如果该
操作没有执行完成(成功或者失败都算是执行完成),则程序会一直阻塞在操作执行的地方,
直到该操作返回一个明确的结果。而非阻塞式程序则不一样,非阻塞式程序会在产生阻塞操
作的地方阻塞一定的时间(该时间可以由程序员自己设置)。如果操作没有完成,在到达所设
置的时间之后,无论该操作成功与否,都结束该操作而执行程序下面的操作。
为了执行非阻塞操作,我们在创建了一个套接口后,需要将套接口设置为非阻塞的套
接口。为了将套接口设置成为非阻塞套接口,我们需要调用 ioctlsocket 函数将套接口设置
为非阻塞的套接口。ioctlsocket 函数的定义如下:
int ioctlsocket( SOCKET s, long cmd, u_long FAR *argp )
该函数的作用是控制套接口的 I/O 模式。
参数 s 表示要设置的套接口;参数 cmd 表示要对该套接口设置的命令,为了要将套
接口设置成为非阻塞的,我们应该填写 FIONBIO;argp 表示填写命令的值,如我们要将
套接口设置成非阻塞的,我们需要将值设置成为 1,如果我们要将套接口设置成为非阻塞状
态的话,我们将值设置成为 0 就是了。
为了进行非阻塞的操作,我们需要在进行操作之前调用 select 函数,select 函数的
定义如下:
int select(int nfds, fd_set FAR *readfds, fd_set FAR *writefds,
fd_set FAR *exceptfds,
const struct timeval FAR *timeout );
该函数设定一个或多个套接口的状态,并进行必要的等待,以便执行异步 I/0(非阻
塞)操作。
参数 nfds 被忽略,该参数的作用仅仅是为了与伯克利套接口相兼容;参数 readfds
表示要检测的可读套接口的集合(该参数可选,可为设置
为 NULL);参数 readfds 表示要检测的可写套接口的集合(该参数可选,可为设置为 NULL);
参数 exceptfds 表示要检测的套接口的错误(该参数可选,可为设置为 NULL);参数 timeo
ut 表示执行该函数时需要等待的时间,如果为 NULL 则表示阻塞操作,为 0 则表示立即返
回。
下面让我们来看看参数类型 fd_set,fd_set 表示套接字的集合。在使用 select 函数
时,我们需要将相应的套接字加入到相应的集合中。如果集合中的套接字有信号,select
函数的返回值即为集合中有信号的套接字数量。
我们用下面的几个宏来操作 fd_set 集合。我们可以使用 FD_SET(s, *set)将套接字
s 加入到集合 set 中;我们可以使用 FD_CLR(s, *set)将套接字 s 移除出集合 set;我们
可以使用 FD_ZERO(*set)将集合 set 清空;最后,我们可以使用 FD_ISSET(s, *set)
来判断套接字 s 是否在集合中有信号。
接下来再让我们来看看 select 函数的三个集合参数 readfds、writefds 以及 exceptf
ds。
readfds 表示可读套接字的集合,可读套接字在三种情况下有信号出现:一、如果集
合中有套接字处于监听状态,并且该套接字上有来自客户端的连接请求;二、如果集合中的
套接字收到了 send 操作发送过来的数据;三、如果集合中的套接字被关闭、重置或者中断。
writefds 表示可写套接字的集合,可写套接字在两种情况下有信号出现:一、集合中
的套接字经过 connect 操作后,连接成功;二、可以用 send 操作向集合中的套接字写数
据。
exceptfds 表示错误套接字的集合,错误套接字在两种情况下有信号出现:一、集合
中的套接字经过 connect 操作后,连接失败;二、有带外数据到来。
在我们了解了创建服务器和客户端程序的基础知识后,我们再来看看示例程序,以加
深我们对知识的理解。
程序的运行结果如下所示:
下面是服务器程序的代码:
view plaincopy to clipboardprint?
1. #include <iostream>
2. #include <cassert>
3. #include <list>
4. #include <WinSock2.h>
5. #pragma comment(lib, "ws2_32.lib")
6. #define ASSERT assert
7. using std::cin;
8. using std::cout;
9. using std::endl;
10. using std::list;
11. typedef list<SOCKET> SocketList;
12. typedef list<SOCKET>::iterator SocketListIterator;
13. static const int c_iPort = 10001;
14. bool GraceClose(SOCKET *ps);
15. int main()
16. {
17. int iRet = SOCKET_ERROR;
18. // 初始化 Winsocket,所有 Winsocket 程序必须先使用 WSAStartup
进行初始化
19. WSADATA data;
20. ZeroMemory(&data, sizeof(WSADATA));
21. iRet = WSAStartup(MAKEWORD(2, 0), &data);
22. ASSERT(SOCKET_ERROR != iRet);
23. // 建立服务端程序的监听套接字
24. SOCKET skListen = INVALID_SOCKET;
25. skListen = socket(AF_INET, SOCK_STREAM, 0);
26. ASSERT(INVALID_SOCKET != skListen);
27. // 初始化监听套接字地址信息
28. sockaddr_in adrServ; // 表示网络地址
29. ZeroMemory(&adrServ, sizeof(sockaddr_in));
30. adrServ.sin_family = AF_INET; // 初始化地址格式,只能
为 AF_INET
31. adrServ.sin_port = htons(c_iPort); // 初始化端口,由于网络
字节顺序和主机字节顺序相反,所以必须使用 htons 将主机字节顺序转换成网络字
节顺序
32. adrServ.sin_addr.s_addr = INADDR_ANY; // 初始化 IP,由于
是服务器程序,所以可以将 INADDR_ANY 赋给该字段,表示任意的 IP
33. // 绑定监听套接字到本地
34. iRet = bind(skListen, (sockaddr*)&adrServ, sizeof(sockaddr_
in));
35. ASSERT(SOCKET_ERROR != iRet);
36. // 使用监听套接字进行监听
37. iRet = listen(skListen, FD_SETSIZE); // SOMAXCONN 表示可以
连接到该程序的最大连接数
38. ASSERT(SOCKET_ERROR != iRet);
39. cout << "Server began listening..." << endl;
40. // 将套接口从阻塞状态设置到费阻塞状态
41. unsigned long ulEnable = 1;
42. iRet = ioctlsocket(skListen, FIONBIO, &ulEnable);
剩余16页未读,继续阅读
资源评论
老帽爬新坡
- 粉丝: 79
- 资源: 2万+
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 笔记实验六,spark,大数据分析
- ####蓝桥杯python的详细的信息介绍
- 电子万年历软件仿真(经过多次修改,保证正确性)
- Unity XR 手势射击控制脚本(适用于任何可手势识别的设备)
- 机械设计全自动电表(NB和IC卡表)控制和上壳装配线sw16可编辑非常好的设计图纸100%好用.zip
- 基于matlab的EAN-13条形码识别系统GUI界面.zip代码53
- matlab基于bp神经网络交通信号标志识别GUI界面13个标志.zip代码54
- 电子万年历答辩实物展示视频mp4格式
- 基于python实现的程序,包括哈希感知算法cvHash,图像切割cvsplit,固定目标检测cvRec(附文档ppt)等
- 计算0-10000之间所有偶数的和
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功