博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Socket阻塞模式和非阻塞模式
阅读量:6301 次
发布时间:2019-06-22

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

       阻塞模式和非阻塞模式

网络不是一个稳定可靠的,存在各种异常情况,比如connect和服务端

三次握手失败,那这个函数就会阻塞,各种问题,可以设置非阻塞,

超时处理,1可以用Socket进行设置,但是考虑到跨平台可能有些函数用不到,   就只能用一种,select多路复用,把socket变成非阻塞模式,

第一步就是把socket设置成非阻塞模式,


        1Windows设置阻塞和非阻塞

1
bool 
setBlock(
bool 
isblock);

有得时候需要阻塞模式,有得时候不需要阻塞模式.主要的目的是

实现超时的控制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bool  
XTCP::SetBlock(
bool 
isblock)
{
if 
(m_sock <= 0)
return 
false
;
unsigned 
long 
ul = 0;
if 
(!isblock)
{
//connect 会立刻返回
ul = 1;
}
// FIONBIO 阻塞模式
//ul =0 表示阻塞模式 
//设置模式
ioctlsocket(m_sock, FIONBIO, &ul);
return 
true
;
}


测试代码, 发现了就是设置false的时候,connect经过的非常快

一下就返回了,但是设置称true的时候,connect就是阻塞的模式会阻塞

几秒钟.

1
2
3
4
5
6
7
8
9
10
#include "XTCP.h"
int 
main(
int 
argc,
char
*argv[])
{
XTCP client;
client.CreateSocket();
client.SetBlock(
false
);
client.Connect(
"192.168.1.125"
,846);
getchar
();
return 
0;
}

         


        2Linux设置阻塞和非阻塞

Windows和Linux的接口函数又不一样了,

头文件  #include <fcntl.h>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
bool  
XTCP::SetBlock(
bool 
isblock)
{
    
if 
(m_sock <= 0)
return 
false
;
    
unsigned 
long 
ul = 0;
    
if 
(!isblock)
    
{
        
//connect 会立刻返回
        
ul = 1;
    
}
    
// FIONBIO 阻塞模式
    
//ul =0 表示阻塞模式 
#ifdef WIN32
    
ioctlsocket(m_sock, FIONBIO, &ul);
#else
    
//操作文件描述法,先获取属性
    
int 
flags = fcntl(m_sock,F_GETFL,0);
    
if 
(flags < 0)
        
return 
false
//出错了
    
if 
(isblock)
    
{
            
//阻塞模式
            
flags = flags &~ O_NONBLOCK;
    
}
    
else
    
{
        
//非阻塞模式
        
flags = flags | O_NONBLOCK;
    
}
    
if
(fcntl(m_sock, F_SETFL, flags)!=0)
    
return 
false
;
#endif
 
    
return 
true
;
}

不过Linux和windows有写不同,是连接的ip存在,但端口不存在

他会立刻反回,所以测试的时候需要把ip改成不存的的测试下.

测试的时候就会发现,false会立刻反回,

他是一个多路复用,不管连接是否成功,放在后端通过select读取

连接信息,这样的话,非阻塞就设置成功

               

          3通过select实现connect跨平台超时处理

重启connect函数,默认我们是1秒钟,

1
bool 
Connect(
const 
char 
*ip, unsigned 
short 
port,
int 
timeoutms=1000);


定义connect

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
bool 
XTCP::Connect(
const 
char 
*ip, unsigned 
short 
port, 
int 
timeoutms)
{
//如果socket没有创建
if 
(m_sock <= 0) CreateSocket();
//连接需要这个结构体
sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);  
//本地字节序转网络字节序
saddr.sin_addr.s_addr = inet_addr(ip);
//改成非阻塞模式
SetBlock(
false
);
//文件句柄数组  存放文件句柄当前的状态
fd_set set;
//这里会立即反回
if 
(connect(m_sock, (sockaddr*)&saddr, 
sizeof
(saddr)) != 0)
{
//给文件句柄数据 置空
FD_ZERO(&set);
//把socket加到这里面
FD_SET(m_sock, &set);
//通过select监听这个文件序列是否有可读或可写
//第一个参数就是监听的所有文件句柄最大值+1 早windows中可有可无,在linu必须设置
//select是可以监听多个文件句柄的  linux中就是文件描述符
//第二个参数是监听的可读的序列  先用不到
//第三个参数是可写的  set是一组文件描述符列表,只要有其中一个可写,
//select函数就返回 如果没有select本身就是阻塞的 如果
//第四个是一个错误处理
//第五个设置超时时间 是一个结构体
//如果成功反回文件描述符的值   如果失败返回-1  ..超时返回0
timeval 
tm
;
tm
.tv_sec = 0; 
//秒
tm
.tv_usec = timeoutms*1000;   
//微秒
if 
(select(m_sock + 1, 0, &set, 0, &
tm
) <= 0)
{
//失败或超时
printf
(
"connect timeout or error!\n"
);
return 
false
;
}
}
//恢复阻塞模式
SetBlock(
true
);
printf
(
"connect %s:%d success!\n"
, ip, port);
return 
true
;
}

在linux编译测试,

测试代码

执行这个客户端的时候,我们默数3秒,然后accent就反回了,

也是是阻塞超时实现. 3000毫秒也就是3秒 一般情况下500毫秒

连接不是就是网络出问题了,

1
2
3
4
5
6
7
8
9
#include "XTCP.h"
int 
main(
int 
argc,
char
*argv[])
{
XTCP client;
client.CreateSocket();
client.Connect(
"192.168.1.13"
,846,3000);
getchar
();
return 
0;
}

效果还是很不错的.

 本文转自超级极客51CTO博客,原文链接:http://blog.51cto.com/12158490/1948229,如需转载请自行联系原作者

你可能感兴趣的文章
关于AJAX框架介绍
查看>>
功能测试的测试工作流程
查看>>
送Vcenter数据库导出虚拟机主要信息报表
查看>>
linux邮件服务器的配置
查看>>
go任务调度9(op实现分布式乐观锁)
查看>>
201621123015《Java程序设计》第8周学习总结
查看>>
dreamweaver批量替换网页超链接
查看>>
热水比冷水结冰快,这就是所谓的姆潘巴现象
查看>>
全球首款桌面蓝牙音箱 不见不散BV600
查看>>
ansible
查看>>
MySQL 运维整体知识框架理解
查看>>
vs2005 使用Speech SDK包含<sphelper.h>报错的问题
查看>>
Windows Server 2012活动目录基础配置与应用(新手教程)之5---用户配置文件
查看>>
js注册登录审核
查看>>
我的友情链接
查看>>
学习笔记1
查看>>
ubuntu14.04下命令安装lamp环境
查看>>
13、【华为HCIE-Storage】--文件协议 CIFS NFS FTP HTTP
查看>>
如何通过连接的端口找出进程
查看>>
linux下面误删root里面的文件夹 恢复方法
查看>>