天天看点

socket 阻塞模式 linux,Socket阻塞模式和非阻塞模式

阻塞模式和非阻塞模式

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

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

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

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

1Windows设置阻塞和非阻塞bool setBlock(bool isblock);

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

实现超时的控制。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就是阻塞的模式会阻塞

几秒钟.#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

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 

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秒钟,bool Connect(const char *ip, unsigned short port,int timeoutms=1000);

定义connectbool 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毫秒

连接不是就是网络出问题了,#include "XTCP.h"

int main(int argc,char*argv[])

{

XTCP client;

client.CreateSocket();

client.Connect("192.168.1.13",846,3000);

getchar();

return 0;

}

效果还是很不错的.