`
aigo
  • 浏览: 2648866 次
  • 性别: Icon_minigender_1
  • 来自: 宜昌
社区版块
存档分类
最新评论

非阻塞socket的连接

 
阅读更多

 

http://doc.chinaunix.net/linux/201002/389886.shtml

 

方案1:

  int connect_socket_timeout(int sockfd,char *dest_host, int port, int timeout)

  {

  struct sockaddr_in address;

  struct in_addr inaddr;

  struct hostent *host;

  int err, noblock=1 , connect_ok=0, begin_time=time(NULL);

  log_debug("connect_socket to %s:%d\n",dest_host,port);

  if (inet_aton(dest_host, &inaddr))

  {

  // log_debug("inet_aton ok now gethostbyaddr %s\n",dest_host);

  memcpy(&address.sin_addr, &inaddr, sizeof(address.sin_addr));

  }

  else

  {

  log_debug("inet_aton fail now gethostbyname %s \n",dest_host);

  host = gethostbyname(dest_host);

  if (!host) {

  /* We can't find an IP number */

  log_error("error looking up host %s : %d\n",dest_host,errno);

  return -1;

  }

  memcpy(&address.sin_addr, host->h_addr_list[0], sizeof(address.sin_addr));

  }

  address.sin_family = AF_INET;

  address.sin_port = htons(port);

  /* Take the first IP address associated with this hostname */

  ioctl(sockfd,FIONBIO,&noblock);

  /** connect until timeout */

  /*

  EINPROGRESS A nonblocking socket connection cannot be completed immediately.

  EALREADY The socket is nonblocking and a previous connection attempt has not been completed.

  EISCONN The socket is already connected.

  */

  if (connect(sockfd, (struct sockaddr *) &address, sizeof(address)) < 0)

  {

  err = errno;

  if (err != EINPROGRESS)

  {

  log_error("connect = %d connecting to host %s\n", err,dest_host);

  }

  else

  {

  // log_notice("connect pending, return %d \n", err);

  while (1) /* is noblocking connect, check it until ok or timeout */

  {

  connect(sockfd, (struct sockaddr *) &address, sizeof(address));

  err = errno;

  switch (err)

  {

  case EISCONN: /* connect ok */

  connect_ok = 1;

  break;

  case EALREADY: /* is connecting, need to check again */

  // log_info("connect again return EALREADY check again...\n");

  usleep(50000);

  break;

  // default: /* failed, retry again ? */

  log_error("connect fail err=%d \n",err);

  // connect_ok = -1;

  // break;

  }

  if (connect_ok==1)

  {

  // log_info ("connect ok try time =%d \n", (time(NULL) - begin_time) );

  break;

  }

  if (connect_ok==-1)

  {

  log_notice ("connect failed try time =%d \n", (time(NULL) - begin_time) );

  break;

  }

  if ( (timeout>0) && ((time(NULL) - begin_time)>timeout) )

  {

  log_notice("connect failed, timeout %d seconds\n", (time(NULL) - begin_time));

  break;

  }

  }

  }

  }

  else /* Connect successful immediately */

  {

  // log_info("connect immediate success to host %s\n", dest_host);

  connect_ok = 1;

  }

  /** end of try connect */

  return ((connect_ok==1)?sockfd:-1);

  }





  方案2:

  补充关于select在异步(非阻塞)connect中的应用,刚开始搞socket编程的时候

  我一直都用阻塞式的connect,非阻塞connect的问题是由于当时搞proxy scan

  而提出的呵呵

  通过在网上与网友们的交流及查找相关FAQ,总算知道了怎么解决这一问题.同样

  用select可以很好地解决这一问题.大致过程是这样的:

  1.将打开的socket设为非阻塞的,可以用fcntl(socket, F_SETFL, O_NDELAY)完

  成(有的系统用FNEDLAY也可).

  2.发connect调用,这时返回-1,但是errno被设为EINPROGRESS,意即connect仍旧

  在进行还没有完成.

  3.将打开的socket设进被监视的可写(注意不是可读)文件集合用select进行监视,

  如果可写,用

  getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, sizeof(int));

  来得到error的值,如果为零,则connect成功.

  在许多unix版本的proxyscan程序你都可以看到类似的过程,另外在solaris精华

  区->编程技巧中有一个通用的带超时参数的connect模块.

  我们知道,缺省状态下的套接字都是阻塞方式的,这意味着一个套接口的调用不能立即完成时,进程将进入睡眠状态,并等待操作完成。对于某些应用,需要及时可控的客户响应,而阻塞的方式可能会导致一个较长的时间段内,连接没有响应。造成套接字阻塞的操作主要有recv, send, accept, connect.

  下面主要以connect为例,讲讲非阻塞的connect的工作原理。当一个TCP套接字设置为非阻塞后,调用connect,会立刻返回一个EINPROCESS的错误。但TCP的三路握手继续进行,我们将用select函数检查这个连接是否建立成功。建立非阻塞的connect有下面三个用途:

  1. 可以在系统做三路握手的时候做些其它事情,这段时间你可以为所欲为。

  2. 可以用这个技术同时建立多个连接,在web应用中很普遍。

  3. 可以缩短connect的超时时间,多数实现中,connect的超时在75秒到几分钟之间,累傻小子呢?

  虽然非阻塞的conncet实现起来并不复杂,但我们必须注意以下的细节:

  * 即使套接字是非阻塞的,如果连接的服务器是在同一台主机,connect通常会立刻建立。(connect 返回 0 而不是 EINPROCESS)

  * 当连接成功建立时,描述字变成可写

  * 当连接出错时,描述字变成可读可写

  例程:定义一个非阻塞的 connect 函数 connect_nonb

  int connect_nonb(int sockfd, const SA *saptr, socklen_t salen, int nsec)

  {

  int flags, n, error;

  socklen_t len;

  fd_set rset, wset;

  struct timeval tval;

  // 获取当前socket的属性, 并设置 noblocking 属性

  flags = fcntl(sockfd, F_GETFL, 0);

  fcntl(sockfd, F_SETFL, flags | O_NOBLOCK);

  errno = 0;

  if ( (n = connect(sockfd, saptr, salen)) < 0)

  if (errno != EINPROGRESS)

  return (-1);

  // 可以做任何其它的操作

  if (n == 0)

  goto done; // 一般是同一台主机调用,会返回 0

  FD_ZERO(&rset);

  FD_SET(sockfd, &rset);

  wset = rset; // 这里会做 block copy

  tval.tv_sec = nsec;

  tval.tv_usec = 0;

  // 如果nsec 为0,将使用缺省的超时时间,即其结构指针为 NULL

  // 如果tval结构中的时间为0,表示不做任何等待,立刻返回

  if ((n = select(sockfd+1, &rset, &west, NULL,nsec ?tval:NULL)) == 0) {

  close(sockfd);

  errno = ETIMEOUT;

  return (-1);

  }

  if(FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &west)) {

  len = sizeof(error);

  // 如果连接成功,此调用返回 0

  if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)

  return (-1);

  }

  else err_quit(“select error: sockfd not set”);

  done:

  fcntl(sockfd, F_SETFL, flags); // 恢复socket 属性

  if (error) {

  close(sockfd);

  errno = error;

  return (-1);

  }

  Return (0);

  }

  注意事项:

  * 如果select调用之前,连接已经建立成功,并且有数据发送过来了,这时套接字将是即可读又可写,和连接失败时是一样的。所以我们必须用getsockopt来检查套接字的状态。

  * 如果我们不能确定套接字可写是成功的唯一情况时,我们可以采用以下的调用

  (1) 调用getpeername,如果调用失败,返回ENOTCONN,表示连接失败

  (2) 调用read,长度参数为0,如果read失败,表示connect失败。

  (3) 再调用connect一次,其应该失败,如果错误是EISCONN,表示套接字已建立而且连接成功。

  * 如果在一个阻塞的套接字上调用的connect,在TCP三路握手前被中断,如果connect不被自动重启,会返回EINTR。但是我们不能调用connect等待连接完成,这样会返回EADDRINUSE,此时我们必须调用select,和非阻塞的方式一样。

分享到:
评论

相关推荐

    非阻塞socket连接

    支持跨平台的非阻塞socket连接,no-block socket connect

    MFC实现非阻塞Socket通信

    在实际应用中,非阻塞Socket通信常用于多用户在线游戏、实时聊天软件、文件传输服务等场景,能够有效地处理并发连接,提高系统资源利用率。结合protobuf,可以实现跨平台、高效的网络数据交换,简化通信协议的设计和...

    Linux下的Socket编程实例(阻塞和非阻塞)

    阻塞和非阻塞Socket Socket 编程中有两种方式:阻塞(Blocking)和非阻塞(Non-Blocking)。阻塞 Socket 指的是在执行某个操作时,程序将等待该操作完成,而非阻塞 Socket 则可以继续执行其他操作,不会被阻塞。 ...

    windows的阻塞和非阻塞Socket编程

    非阻塞Socket(Non-blocking Socket)则提供了另一种解决方案。在非阻塞模式下,当尝试读取数据但缓冲区为空,或者尝试写入但网络不可写时,recv()和send()函数并不会挂起,而是立即返回一个错误代码。开发者需要...

    C++ socket 阻塞与非阻塞

    本话题主要探讨的是在C++ Socket编程中的阻塞模式与非阻塞模式,以及它们在多线程环境下的应用和资源管理。 一、阻塞与非阻塞模式 1. **阻塞模式**:在阻塞模式下,当一个Socket调用(如recv或send)执行时,如果...

    python多线程非阻塞socket

    非阻塞Socket允许Socket在等待数据时不会被挂起,而是立即返回,这样可以提高系统的整体效率。 在Python中,我们可以使用`threading`模块来创建和管理线程。创建一个线程的基本步骤包括定义一个运行函数,然后创建...

    非阻塞Socket的应用

    2. **客户端**:使用非阻塞Socket与服务器建立连接,发送和接收消息。客户端也需要注册事件处理器,以便在数据准备好时进行读取,或者在可以发送数据时进行写入。 3. **消息协议**:为了保证数据的正确传输,聊天...

    socket 多线程 例程 非阻塞模式

    在VC++6.0中,我们可以使用`_beginthread`或`CreateThread`函数来创建新线程,每个线程负责一个socket连接的处理。 非阻塞模式是socket通信中的一个重要特性。在默认情况下,socket操作是阻塞的,即调用send、recv...

    非阻塞模式socket程序

    回调函数在非阻塞Socket编程中起着关键作用。当接收到数据或发生特定事件(如连接、断开连接)时,程序会通过预先注册的回调函数通知应用层。这种方式使得处理网络事件更加灵活,应用可以根据自身需求定制事件处理...

    Socket C++ TCP阻塞\非阻塞 服务器 客户端 开发

    4. **关闭连接**:关闭socket连接。 5. **设置非阻塞模式**:使用`ioctlsocket`函数来设置工作模式。 示例代码: ```cpp class CSocket { public: CSocket() : m_sock(INVALID_SOCKET) {} ~CSocket() { if (m_...

    Linux UDP socket 设置为的非阻塞模式与阻塞模式区别

    ### Linux UDP Socket 非阻塞模式与阻塞模式的区别详解 #### 一、引言 在进行网络编程时,我们经常会遇到阻塞模式与非阻塞模式的选择问题。这两种模式直接影响程序的运行效率和资源利用率。本文将详细介绍在Linux...

    feizuse.rar_C socket 非阻塞_网络服务_非阻塞_非阻塞 socket

    "feizuse.rar"中的源码可能包含了一个简单的网络服务器示例,展示了如何在Windows环境下创建非阻塞`socket`,设置异步事件,并响应来自客户端的连接请求和数据传输。通过分析和学习这个源码,我们可以了解到以下关键...

    基于多线程的非阻塞 socket 编程

    # 基于多线程的非阻塞Socket编程教程 ## 简介 基于多线程的非阻塞Socket编程是一种高效处理网络通信的技术,结合了多线程编程和非阻塞I/O。它用于构建高性能的网络服务器和客户端,可以同时处理多个连接而不使线程...

    C++封装类CWSocket(多线程 非阻塞)

    通过阅读和分析这些代码,我们可以深入了解如何在C++中实现多线程、非阻塞的socket类,以及如何添加超时控制。 总的来说,C++封装类CWSocket的实现结合了多线程、非阻塞I/O和超时处理等关键技术,旨在提供一个高效...

    异步非阻塞socket聊天室程序

    "异步非阻塞socket聊天室程序"是一个使用C++语言,并基于MFC(Microsoft Foundation Classes)库构建的项目,旨在实现高效的多用户通信。下面将详细阐述这个程序背后的关键知识点。 首先,我们关注的是"异步非阻塞...

    Nio非阻塞socket通信demo

    在这个“Nio非阻塞socket通信demo”中,我们可以深入理解NIO在Socket通信中的应用。 1. **Java NIO基础** - **通道(Channels)**:NIO的核心概念之一,通道是数据读写的目标或来源,如文件通道、套接字通道等。...

    使用AIO实现非阻塞socket通信

    非阻塞socket通信与传统的阻塞I/O模式不同,阻塞模式会在数据未准备好时挂起线程,直到数据可读或可写。而非阻塞模式下,当请求的数据未准备好时,系统会立即返回一个状态,让调用者可以继续执行其他任务,等到数据...

    使用NIO实现非阻塞socket通信

    本项目利用NIO实现了一个简单的非阻塞socket通信的聊天工具,使得在高并发环境下,服务器能够同时处理多个客户端连接,提高系统性能。 1. **非阻塞I/O**: 在BIO模型中,读写操作是阻塞的,即当没有数据可读或无法...

    Socket通信(TCP)非阻塞模式-select模型

    "Socket 通信(TCP)非阻塞模式-select 模型" 本资源是关于 Socket 通信的非阻塞模式下的 Select 模型的示例代码,基于 TCP 协议,分为服务器端和客户端。该示例代码展示了如何使用 Select 模型实现非阻塞 Socket ...

Global site tag (gtag.js) - Google Analytics