转载请注明来源:https://www.cnblogs.com/hookjc/

linux下socket编程有常见的几个系统调用:

对于服务器来说, 有socket(), bind(),listen(), accept(),read(),write()

对于客户端来说,有socket(),connect()

这里主要要讲的是客户端这边的connect函数。

对于客户端来说,需要打开一个套接字,然后与对端服务器连接,例如:


 1 int main(int argc, char **argv)
2 {
3 struct sockaddr_in s_addr;
4 memset(&s_addr, 0, sizeof(s_addr));
5 s_addr.sin_family = AF_INET;
6 s_addr.sin_addr.s_addr = inet_addr("remote host");
7 s_addr.sin_port = htons(remote port);
8 socklen_t addr_len = sizeof(struct sockaddr);
9 int c_fd = socket(AF_INET, SOCK_STREAM, 0);
10 int ret = connect(c_fd, (struct sockaddr*)&s_addr, addr_len);
11 ......
12 }

当connect上对端服务器之后,就可以使用该套接字发送数据了。

我们知道,如果socket为TCP套接字, 则connect函数会激发TCP的三次握手过程,而三次握手是需要一些时间的,内核中对connect的超时限制是75秒,就是说如果超过75秒则connect会由于超时而返回失败。但是如果对端服务器由于某些问题无法连接,那么每一个客户端发起的connect都会要等待75才会返回,因为socket默认是阻塞的。对于一些线上服务来说,假设某些对端服务器出问题了,在这种情况下就有可能引发严重的后果。或者在有些时候,我们不希望在调用connect的时候阻塞住,有一些额外的任务需要处理;

这种场景下,我们就可以将socket设置为非阻塞,如下代码:

int flags = fcntl(c_fd, F_GETFL, 0);
if(flags < 0) {
return 0;
}
fcntl(c_fd, F_SETFL, flags | O_NONBLOCK);

当我们将socket设置为NONBLOCK后,在调用connect的时候,如果操作不能马上完成,那connect便会立即返回,此时connect有可能返回-1, 此时需要根据相应的错误码errno,来判断连接是否在继续进行。

当errno=EINPROGRESS时,这种情况是正常的,此时连接在继续进行,但是仍未完成;同时TCP的三路握手操作继续进行;后续只要用select/epoll去注册对应的事件并设置超时时间来判断连接否是连接成功就可以了。


int ret = connect(c_fd, (struct sockaddr*)&s_addr, addr_len);
while(ret < 0) {
if( errno == EINPROGRESS ) {
break;
} else {
perror("connect fail'\n");
return 0;
}
}

这个地方,我们很可能会判断如果ret小于0,就直接判断连接失败而返回了,没有根据errno去判断EINPROGRESS这个错误码。这里也是昨天在写份程序的时候遇到的一个坑。

使用非阻塞 connect 需要注意的问题是:
1. 很可能 调用 connect 时会立即建立连接(比如,客户端和服务端在同一台机子上),必须处理这种情况。
2. Posix 定义了两条与 select 和 非阻塞 connect 相关的规定:
1)连接成功建立时,socket 描述字变为可写。(连接建立时,写缓冲区空闲,所以可写)
2)连接建立失败时,socket 描述字既可读又可写。 (由于有未决的错误,从而可读又可写)

不过我同时用epoll也做了实验(connect一个无效端口,errno=110, errmsg=connect refused),当连接失败的时候,会触发epoll的EPOLLERR与EPOLLIN,不会触发EPOLLOUT。

当用select检测连接时,socket既可读又可写,只能在可读的集合通过getsockopt获取错误码。

当用epoll检测连接时,socket既可读又可写,只能在EPOLLERR中通过getsockopt获取错误码。

完整代码如下:


/*
* File: main.cpp
* Created on March 7, 2013, 5:54 PM
*/ #include <cstdlib>
#include <string>
#include <iostream> #include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <error.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h> using namespace std; struct so {
int fd;
string val;
}; int select_version(int *fd) {
int c_fd = *fd;
fd_set rset, wset;
struct timeval tval;
FD_ZERO(&rset);
FD_SET(c_fd, &rset);
wset = rset;
tval.tv_sec = 0;
tval.tv_usec = 300 * 1000; //300毫秒
int ready_n;
if ((ready_n = select(c_fd + 1, &rset, &wset, NULL, &tval)) == 0) {
close(c_fd); /* timeout */
errno = ETIMEDOUT;
perror("select timeout.\n");
return (-1);
}
if (FD_ISSET(c_fd, &rset)) {
int error;
socklen_t len = sizeof (error);
if (getsockopt(c_fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
cout << "getsockopt error." << endl;
return -1;
}
// cout << "in fire." << error << endl;
}
if (FD_ISSET(c_fd, &wset)) {
int error;
socklen_t len = sizeof (error);
if (getsockopt(c_fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
cout << "getsockopt error." << endl;
return -1;
}
// cout << "out fire." << error << endl;
}
return 0;
} int epoll_version(int *fd) {
int c_fd = *fd;
int ep = epoll_create(1024);
struct epoll_event event;
event.events = (uint32_t) (EPOLLIN | EPOLLOUT | EPOLLET);
struct so _data;
_data.fd = c_fd;
_data.val = "test";
event.data.ptr = (void*) &_data;
epoll_ctl(ep, EPOLL_CTL_ADD, c_fd, &event);
struct epoll_event eventArr[1000];
int status, err;
socklen_t len;
err = 0;
len = sizeof (err);
int n = epoll_wait(ep, eventArr, 20, 300); // 300ms
for (int i = 0; i < n; i++) {
epoll_event ev = eventArr[i];
int events = ev.events;
if (events & EPOLLERR) {
struct so* so_data = (struct so*) ev.data.ptr;
cout << so_data->val << ",err event fire." << endl;
status = getsockopt(c_fd, SOL_SOCKET, SO_ERROR, &err, &len);
cout << status << "," << err << endl;
            return -1;
}
if (events & EPOLLIN) {
struct so* so_data = (struct so*) ev.data.ptr;
cout << so_data->val << ",in event fire." << endl;
status = getsockopt(c_fd, SOL_SOCKET, SO_ERROR, &err, &len);
cout << status << "," << err << endl;
        }
if (events & EPOLLOUT) {
struct so* so_data1 = (struct so*) ev.data.ptr;
cout << so_data1->val << ",out event fire." << endl;
}
}
return 0;
} int main(int argc, char** argv) {
string ip = "127.0.0.1";
int port = 25698;
int c_fd, flags, ret;
struct sockaddr_in s_addr;
memset(&s_addr, 0, sizeof (s_addr));
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(port);
s_addr.sin_addr.s_addr = inet_addr(ip.c_str()); if ((c_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("create socket fail.\n");
exit(0);
}
flags = fcntl(c_fd, F_GETFL, 0);
if (flags < 0) {
perror("get socket flags fail.\n");
return -1;
} if (fcntl(c_fd, F_SETFL, flags | O_NONBLOCK) < 0) {
perror("set socket O_NONBLOCK fail.\n");
return -1;
}
ret = connect(c_fd, (struct sockaddr*) &s_addr, sizeof (struct sockaddr));
if (ret < 0) {
if (errno != EINPROGRESS) { exit(0);
}
}
    if (epoll_version(&c_fd) < 0)//select_version(&c_fd);
    {
        perror("epoll connect remote server fail.\n");
        printf("%d\n", errno);
        exit(0);
    }
    // send data

    // recv data

    return 0;
}

来源:python脚本自动迁移

linux 设置connect 超时代码[select/epoll]的更多相关文章

  1. linux 设置connect 超时

    转载请注明来源:https://www.cnblogs.com/hookjc/ 将一个socket 设置成阻塞模式和非阻塞模式,使用fcntl方法,即: 设置成非阻塞模式: 先用fcntl的F_GET ...

  2. Linux下connect超时处理【总结】

    1.前言 最近在写一个测试工具,要求快速的高效率的扫描出各个服务器开放了哪些端口.当时想了一下,ping只能检测ip,判断服务器的网络是连通的,而不能判断是否开放了端口.我们知道端口属于网络的应用层, ...

  3. Linux下connect超时处理

    1.前言 最近在写一个测试工具,要求快速的高效率的扫描出各个服务器开放了哪些端口.当时想了一下,ping只能检测ip,判断服务器的网络是连通的,而不能判断是否开放了端口.我们知道端口属于网络的传输层, ...

  4. linux网络编程 IO多路复用 select epoll

    本文以我的小型聊天室为例,对于服务器端的代码,做了三次改进,我将分别介绍阻塞式IO,select,epoll . 一:阻塞式IO 对于聊天室这种程序,我们最容易想到的是在服务器端accept之后,然后 ...

  5. iOS 设置connect超时

    NSLock *theLock; [theLock lock]; int fd, error; struct sockaddr_in addr; ))<) { cout<<" ...

  6. linux下connect超时时间探究

    最近在linux做服务器开发的时候,发现了一个现象:服务器在启动的时候调用了 connect 函数,因为连接了一个不可用的端口,导致connect最后报出了 “Connection timed out ...

  7. VC socket Connect 超时时间设置

    设置connect超时很简单,CSDN上也有人提到过使用select,但却没有一个令人满意与完整的答案.偶所讲的也正是select函数,此函数集成在winsock1.1中,简单点讲,"作用使 ...

  8. C Socket编程之Connect超时 (转)

    网络编程中socket的分量我想大家都很清楚了,socket也就是套接口,在套接口编程中,提到超时的概念,我们一下子就能想到3个:发送超时,接收超时,以及select超时(注:select函数并不是只 ...

  9. 设置linux中tcp默认的20秒connect超时时间(转)

    无论你用任何语言或者是网络库,你都可以设置网络操作的超时时间,特别是connect.read.write的超时时间. 你可以在代码中把超时时间设置任意大小值,但是connect方法会有一点特殊. co ...

随机推荐

  1. x86-2-保护模式(protect mode)

    x86-2-保护模式(protect mode) 引入保护模式的原因: 操作系统负责计算机上的所有软件和硬件的管理,它可以百分百操作计算机的所有内容.但是,操作系统上编写的用户程序却应当有所限制,比如 ...

  2. 初识python: 字符串常用操作

    直接上代码示例: #!/user/bin env python # author:Simple-Sir # time:20180914 # 字符串常用操作 name = 'lzh lyh' print ...

  3. linux如何查看服务器当前的并发访问量

    linux如何查看服务器当前的并发访问量 [root@localhost ~]# netstat -pnt | grep :80 | wc -l 2 [root@localhost ~]# netst ...

  4. idea 开启 tomcat 热部署 的 具体流程 和 使用方式

    1前言 一直以来,使用idea做web开发修改html.jsp.js文件后,必须手动重新部署tomcat,最少都有等个6 -10 秒, 甚至有时候还提示找不到某个编译文件报错,重新编译整个项目,那得等 ...

  5. SYCOJ1613递归函数

    题目-递归函数 (shiyancang.cn) 记忆化dfs,注意dp的限制范围 #include<bits/stdc++.h> using namespace std; const in ...

  6. php反序列化之pop链构造

    本题是某信有一次内部比赛的题目,涉及到pop链的构造问题,所以在这里与大家分享一下 题目 查看源码 逻辑是当参数fn存在且不包含string.zlib.flag这三个字符串时,进行文件包含这里的过滤是 ...

  7. Java反射详解:入门+使用+原理+应用场景

    反射非常强大和有用,现在市面上绝大部分框架(spring.mybatis.rocketmq等等)中都有反射的影子,反射机制在框架设计中占有举足轻重的作用. 所以,在你Java进阶的道路上,你需要掌握好 ...

  8. 解决excel两表之间数据关联关系,知道这几招就够了

    用过SAP的凭证批量录入模板(Excel文件)的都知道,一个凭证由[抬头]和多个[行项目]组成,这是一个关于excel两表信息关联的典型场景. 这里头蕴藏着一个麻烦:当我们需要一次性录入多个凭证时,如 ...

  9. JVM组成详解

    一.JVM 整体组成 JVM 整体组成可分为以下四个部分: 类加载器(ClassLoader) 运行时数据区(Runtime Data Area) 执行引擎(Execution Engine) 本地库 ...

  10. 如何使用Github搭建自己的博客

    1.前期准备 sudo apt-get install npm sudo npm install hexo -g 首先使用如下命令创建项目,name是你要创建的博客的名字: hexo init {na ...