最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Linux下connect超時處理(總結)

 更新時間:2017年04月26日 16:51:50   作者:Anker''s Blog  
這篇文章主要介紹了Linux下connect超時處理(總結),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

1、前言

最近在寫一個測試工具,要求快速的高效率的掃描出各個服務器開放了哪些端口。當時想了一下,ping只能檢測ip,判斷服務器的網(wǎng)絡是連通的,而不能判斷是否開放了端口。我們知道端口屬于網(wǎng)絡的傳輸層,因此需要用ip和端口來探測,這個時候就可以用connect來探測一下,針對TCP協(xié)議,connect函數(shù)要進行TCP三次握手,如果connect成功,則說明服務器開放了某個端口,如果connect失敗,則說明服務器沒有開放某個端口。而connect失敗是通過超時來控制的,在規(guī)定的時間內,connect會發(fā)起多次連接,一直執(zhí)行到超時,才返回錯誤。默認情況下,connect是阻塞的,而且默認的超時時間為75s,正常情況下,檢測網(wǎng)絡的連通性都是毫秒級,如果要判斷10萬臺服務器的,用阻塞的默認的connect去做,效率非常低下。因此采用非阻塞的connect,而且需要自定義超時間(我自定義超時時間為5s)。

2、非阻塞connect

對于阻塞式套接字,調用connect函數(shù)將激發(fā)TCP的三次握手過程,而且僅在連接建立成功或者出錯時才返回;對于非阻塞式套接字,如果調用connect函數(shù)會之間返回-1(表示出錯),且錯誤為EINPROGRESS,表示連接建立,建立啟動但是尚未完成;如果返回0,則表示連接已經(jīng)建立,這通常是在服務器和客戶在同一臺主機上時發(fā)生。

select是一種IO多路復用機制,它允許進程指示內核等待多個事件的任何一個發(fā)生,并且在有一個或者多個事件發(fā)生或者經(jīng)歷一段指定的時間后才喚醒它。connect本身并不具有設置超時功能,如果想對套接字的IO操作設置超時,可使用select函數(shù)。

對于select和非阻塞connect,注意兩點:[1] 當連接成功建立時,描述符變成可寫; [2] 當連接建立遇到錯誤時,描述符變?yōu)榧纯勺x,也可寫,遇到這種情況,可調用getsockopt函數(shù)。

3、實現(xiàn)步驟

(1) 創(chuàng)建socket,并利用fcntl將其設置為非阻塞

(2) 調用connect函數(shù),如果返回0,則連接建立;如果返回-1,檢查errno ,如果值為 EINPROGRESS,則連接正在建立。

(3) 為了控制連接建立時間,將該socket描述符加入到select的可讀可寫集合中,采用select函數(shù)設定超時。

(4) 如果規(guī)定時間內成功建立,則描述符變?yōu)榭蓪懀环駝t,采用getsockopt函數(shù)捕獲錯誤信息

(5) 恢復套接字的文件狀態(tài)并返回。

測試代碼如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>     /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>

int main(int argc, char **argv)
{
  if (argc < 3) {
    printf("please input ip and port, for example ./main 120.12.34.56 80.\n");
    return -1;
  }

  
  char *ipaddr = argv[1];
  unsigned int port = atoi(argv[2]);

  int fd = 0;
  struct sockaddr_in addr;
  fd_set fdr, fdw;
  struct timeval timeout;
  int err = 0;
  int errlen = sizeof(err);

  fd = socket(AF_INET,SOCK_STREAM,0);
  if (fd < 0) {
    fprintf(stderr, "create socket failed,error:%s.\n", strerror(errno));
    return -1;
  }

  bzero(&addr, sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_port = htons(port);
  inet_pton(AF_INET, ipaddr, &addr.sin_addr);

  /*設置套接字為非阻塞*/
  int flags = fcntl(fd, F_GETFL, 0);
  if (flags < 0) {
    fprintf(stderr, "Get flags error:%s\n", strerror(errno));
    close(fd);
    return -1;
  }
  flags |= O_NONBLOCK;
  if (fcntl(fd, F_SETFL, flags) < 0) {
    fprintf(stderr, "Set flags error:%s\n", strerror(errno));
    close(fd);
    return -1;
  }

  /*阻塞情況下linux系統(tǒng)默認超時時間為75s*/
  int rc = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
  if (rc != 0) {
    if (errno == EINPROGRESS) {
      printf("Doing connection.\n");
      /*正在處理連接*/
      FD_ZERO(&fdr);
      FD_ZERO(&fdw);
      FD_SET(fd, &fdr);
      FD_SET(fd, &fdw);
      timeout.tv_sec = 10;
      timeout.tv_usec = 0;
      rc = select(fd + 1, &fdr, &fdw, NULL, &timeout);
      printf("rc is: %d\n", rc);
      /*select調用失敗*/
      if (rc < 0) {
        fprintf(stderr, "connect error:%s\n", strerror(errno));
        close(fd);
        return -1;
      }
      
      /*連接超時*/
      if (rc == 0) {
        fprintf(stderr, "Connect timeout.\n");
        close(fd);
        return -1;
      }
      /*[1] 當連接成功建立時,描述符變成可寫,rc=1*/
      if (rc == 1 && FD_ISSET(fd, &fdw)) {
        printf("Connect success\n");
        close(fd);
        return 0;
      }
      /*[2] 當連接建立遇到錯誤時,描述符變?yōu)榧纯勺x,也可寫,rc=2 遇到這種情況,可調用getsockopt函數(shù)*/
      if (rc == 2) {
        if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
          fprintf(stderr, "getsockopt(SO_ERROR): %s", strerror(errno));
          close(fd);
          return -1;

        }

        if (err) {
          errno = err;
          fprintf(stderr, "connect error:%s\n", strerror(errno));
          close(fd);
          return -1;

        }
      }

    } 
    fprintf(stderr, "connect failed, error:%s.\n", strerror(errno));
    return -1;
  } 
  return 0;
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • Linux下如何查看版本信息的方法步驟

    Linux下如何查看版本信息的方法步驟

    這篇文章主要介紹了Linux下如何查看版本信息的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12
  • Apache Web 服務器的安裝配置方法

    Apache Web 服務器的安裝配置方法

    學習如何在 Apache 上托管你自己的網(wǎng)站,這是一個可靠、流行且易于配置的 Web 服務器。Apache Web 服務器的安裝和配置必須以 root 身份執(zhí)行,接下來通過本文給大家介紹Apache Web 服務器的安裝配置方法,需要的朋友參考下吧
    2018-10-10
  • vagrant如何啟動虛擬機

    vagrant如何啟動虛擬機

    本文介紹了使用Vagrant和VirtualBox快速搭建Linux虛擬機的過程,包括創(chuàng)建Vagrantfile、配置網(wǎng)絡、使用SSH連接以及賬戶配置等步驟
    2024-11-11
  • Linux防火墻設置允許特定IP訪問指定端口

    Linux防火墻設置允許特定IP訪問指定端口

    文章介紹了服務器安全設置,包括啟用防火墻、檢查端口、關閉端口訪問、添加特定IP訪問特定端口的方法步驟,以及注意事項
    2025-04-04
  • Linux中如何將txt文件轉為png格式

    Linux中如何將txt文件轉為png格式

    這篇文章主要介紹了Linux中如何將txt文件轉為png格式問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Linux?LVM邏輯卷相關管理方式

    Linux?LVM邏輯卷相關管理方式

    這篇文章主要介紹了Linux?LVM邏輯卷相關管理方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • Linux系統(tǒng)交換空間介紹

    Linux系統(tǒng)交換空間介紹

    今天小編就為大家分享一篇關于Linux系統(tǒng)交換空間介紹的文章,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-09-09
  • 銀河麒麟4.0.2(Ubuntu)擴展boot分區(qū)過程介紹

    銀河麒麟4.0.2(Ubuntu)擴展boot分區(qū)過程介紹

    大家好,本篇文章主要講的是銀河麒麟4.0.2(Ubuntu)擴展boot分區(qū)過程介紹,感興趣的同學快來看一看吧,對你有幫助的話記得收藏一下哦
    2021-11-11
  • Linux模擬網(wǎng)絡丟包與延遲的方法

    Linux模擬網(wǎng)絡丟包與延遲的方法

    這篇文章主要給大家介紹了關于Linux模擬網(wǎng)絡丟包與延遲的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Linux具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-05-05
  • Linux獲取當前腳本真實路徑的方法

    Linux獲取當前腳本真實路徑的方法

    今天小編就為大家分享一篇關于Linux獲取當前腳本真實路徑的方法,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03

最新評論

光山县| 洪洞县| 商都县| 鄂伦春自治旗| 龙江县| 织金县| 宁陕县| 郎溪县| 白银市| 肥西县| 德钦县| 四平市| 新乡市| 桂平市| 曲松县| 宝坻区| 玉山县| 郓城县| 浦北县| 兴文县| 安溪县| 陈巴尔虎旗| 马龙县| 南部县| 虞城县| 哈密市| 轮台县| 湛江市| 阿拉善盟| 木兰县| 宽甸| 德州市| 双流县| 四平市| 沙雅县| 瓦房店市| 昭觉县| 河曲县| 潍坊市| 枣庄市| 马龙县|