1. 程式人生 > >Linux下Socket連線超時的一種實現方法

Linux下Socket連線超時的一種實現方法

目前各平臺通用的設定套接字(Socket)連線超時的辦法是:
  1. 建立套接字,將其設定成非阻塞狀態。
  2. 呼叫connect連線對端主機,如果失敗,判斷當時的errno是否為EINPROGRESS,也就是說是不是連線正在進行中,如果是,轉到步驟3,如果不是,返回錯誤。
  3. 用select在指定的超時時間內監聽套接字的寫就緒事件,如果select有監聽到,證明連線成功,否則連線失敗。
  以下是Linux環境下的示例程式碼:



#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>


#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <time.h>

int main(int argc, char *argv[])
{
        int fd, retval;
        struct sockaddr_in addr;
        struct timeval timeo = {3, 0};
        socklen_t len = sizeof(timeo);
        fd_set set
;

        fd = socket(AF_INET, SOCK_STREAM, 0);
        if (argc == 4)
                timeo.tv_sec = atoi(argv[3]);
        fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = inet_addr(argv[1]);
        addr.sin_port = htons(atoi(argv[
2]));
        printf("%dn", time(NULL));
        if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
                printf("connectedn");
                return 0;
        }
        if (errno != EINPROGRESS) {
                perror("connect");
                return -1;
        }
        FD_ZERO(&set);
        FD_SET(fd, &set);
        retval = select(fd + 1, NULL, &set, NULL, &timeo);
        if (retval == -1) {
                perror("select");
                return -1;
        } else if(retval == 0) {
                fprintf(stderr, "timeoutn");
                printf("%dn", time(NULL));
                return 0;
        }
        printf("connectedn");

        return 0;
}


  實際執行結果如下:

[email protected] perl \$ ./a.out 10.16.101.1 90
1180289276
timeout
1180289279
[email protected] perl \$ ./a.out 10.16.101.1 90 1
1180289281
timeout
1180289282

  可以看到,以上程式碼工作的很好,並且如果你想知道連線發生錯誤時的確切資訊的話,你可以用getsocketopt獲得:

int error;
socklen_t errorlen = sizeof(error);

getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &errorlen);


  但是多少有些複雜,如果有象SO_SNDTIMO/SO_RCVTIMO一樣的套接字引數可以讓超時操作跳過select的話,世界將變得更美好。當然你還可以選用象apr一樣提供了簡單介面的庫,但我這裡要提的是另一種方法。

  呵呵,引子似乎太長了點兒。讀Linux核心原始碼的時候偶然發現其connect的超時引數竟然和用SO_SNDTIMO操作的引數一致:

  File: net/ipv4/af_inet.c

   559      timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
   560
   561      if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
   562          /* Error code is set above */
   563          if (!timeo || !inet_wait_for_connect(sk, timeo))
   564              goto out;
   565
   566          err = sock_intr_errno(timeo);
   567          if (signal_pending(current))
   568              goto out;
   569      }

  這意味著:在Linux平臺下,可以通過在connect之前設定SO_SNDTIMO來達到控制連線超時的目的。簡單的寫了份測試程式碼:


#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>

int main(int argc, char *argv[])
{
        int fd;
        struct sockaddr_in addr;
        struct timeval timeo = {3, 0};
        socklen_t len = sizeof(timeo);

        fd = socket(AF_INET, SOCK_STREAM, 0);
        if (argc == 4)
                timeo.tv_sec = atoi(argv[3]);
        setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, len);
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = inet_addr(argv[1]);
        addr.sin_port = htons(atoi(argv[2]));
        if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
                if (errno == EINPROGRESS) {
                        fprintf(stderr, "timeoutn");
                        return -1;
                }
                perror("connect");
                return 0;
        }
        printf("connectedn");

        return 0;
}


  執行結果:

[email protected] perl \$ ./a.out 10.16.101.1 90
1180290583
timeout
1180290586
[email protected] perl \$ ./a.out 10.16.101.1 90 2
1180290590
timeout
1180290592

  和設想完全一致!

相關推薦

LinuxSocket連線超時實現方法

目前各平臺通用的設定套接字(Socket)連線超時的辦法是: 建立套接字,將其設定成非阻塞狀態。呼叫connect連線對端主機,如果失敗,判斷當時的errno是否為EINPROGRESS,也就是說是不是連線正在進行中,如果是,轉到步驟3,如果不是,返回錯誤。用select在指定的超時時間內監聽套接字的寫就

Linux 程序間通訊的實現方式

程序間通訊的方式一般有三種:管道(普通管道、流管道和命名管道)、系統IPC(訊息佇列、訊號和共享儲存)、套接字(Socket) 本部落格以之前所做的智慧車專案為例,簡單介紹下共享儲存的一種實現過程。簡單說來,程序1將資料寫入到一個公共檔案input.txt中,程序2對其進行

linuxsocket connect超時設定

[From]http://www.ycgczj.com.cn/34733.html 網路程式設計中socket的分量我想大家都很清楚了,socket也就是套介面,在套介面程式設計中,提到超時的概念,我們一下子就能想到3個:傳送超時,接收超時,以及select超時(注: select函式並不是只用於套介面的

Linuxsocket程式設計之UDP簡單實現

本文實現一個簡單的UDP小例子,來說明Linux下socket程式設計之UDP的簡單實現。本文主要包括三個部分:伺服器端的實現,客服端的實現和通訊測試。實現的功能:客服端傳送一條訊息給伺服器端,伺服器

C++差分隱私的指數機制的實現方法

list and span 機制 namespace stdio.h int class ++ #include <iostream> #include<stdio.h> #include<stdlib.h> #include<m

nginx 301重定向實現方法

pan listen lis return uri www com 瀏覽器 request 1 假設要使用的域名是b.com,以前的老域名是a.com,則以下設置讓nginx把a.com的請求訪問轉發到b.com,並返回301給瀏覽器。 2 server 3

最大子矩陣的實現方法

targe 空間 pos 右下角 ont 算法 algo 最大子矩陣 AC 題目: 農夫約翰想要在他的正方形農場上建造一座正方形大牛棚。他討厭在他的農場中砍樹,想找一個能夠讓他在空曠無樹的地方修建牛棚的地方。我們假定,他的農場劃分成 N x N 的方格。輸入數據中包括

MMVVC設計方法介紹:經典MVC設計模式在Cocoa-MVC中的實現方法

MVC介紹 MVC在WEB開發中用於界定工作屬於Server端還是WEB前端還是十分清晰的。這也就是大家目前常見的MVC設計模式: View<===>Controller<===>Model 即Controller作為粘合劑分別於View和Model進行雙向通訊。

CSS:多個DIV在同一行居中顯示的實現方法

在專案開發中,畫面經常有多個DIV的內容顯示在一行的要求。 比如HTML <div class="div_allinline"> <div class="subdiv_allinline"> 你好,這是div1的第一行。 &

linux fork() 程序樹的兩實現方法

Linux fork()程序樹的兩種實現方法 剛完成作業系統的實驗一,其中附加題是使用fork()實現一顆滿二叉樹形態的程序樹,覺得好玩,做完之後就記錄一下。 1. 暴力的做法 最簡單粗暴的做法,當然就是直接把層數寫死啦。例如要建立三層的程序樹,就

Laravel 5.3 使用內建的 Auth 元件實現多使用者認證功能以及登陸才能訪問後臺的功能的實現方法

概述 在開發中,我們經常會遇到多種型別的使用者的認證問題,比如後臺的管理員和前臺的普通使用者。Laravel 5.3 內建的 Auth 元件已經能很好的滿足這項需求,下面大概記錄下使用方法。 另外,後臺頁面常常需要登入才能訪問,為了完成類似的功能,大家一般都

中文通訊錄排序的實現方法

在我們通訊錄中,聯絡人都是按一定的順序(字典順序)從上到下排列的。那麼對於儲存為中文的聯絡人,它的排序是怎樣實現的呢? 現行比較好理解,容易想到又通用的方法是先將中文轉換為拼音形式,再根據拼音各字母的ACSII碼大小比較從而實現排序目的。 1、申請兩個陣列A

Sticky Header的另實現方法

使用Sticky Header的list單個item一般情況下使用的資料結構是 {data:"what's inside", category:"section name"} 這樣儲存其實是浪費了很多的空間,因為category的名字被儲存的多次。在移動環境

C++中建立物件間訊息連線系統方法——回撥函式

C++中建立物件間訊息連線的一種系統方法——回撥函式作者:項飛 用過C++進行過面向物件程式設計的使用者都知道,程式中的物件很少單獨存在。不考慮物件間的相互作用幾乎是不可能的。所以,標識物件間的關係或建立物件間的訊息連線是面向物件程式設計的一項重要任務。本文著重從C++程式

Unity 全域性遊戲指令碼的實現方法

public class GlobalScript : MonoBehaviour { public static GlobalScript instance; void Awake() { if (instance == null) { // 判定 nu

ArrayList深拷貝的實現方法

大家應該理解淺拷貝和深拷貝的區別: 淺拷貝:被複制物件的任何變數都含有和原來的物件相同的值,而任何的對其他物件的引用仍然指向原來的物件。對拷貝後的引用的修改,還能影響原來的物件。 深拷貝:把要複製的物件所引用的物件都複製了一遍,對現在物件的修改不會影響原有的物件。

LabWindows/CVI與Matlab混合程式設計的實現方法

最近一段時間都在學習基於LabWindows/CVI(後文簡稱CVI)開發模擬軟體,由於已有一個不太穩健,但基本框架較為齊備的工程。所以我的工作主要是在這個已有的工程上進行debug、整理修改、開發新功能,從5月開始已經持續了接近三個月。 在之前的開發過程中我

c++ 網絡編程(六)TCP/IP LINUX socket編程 多播與廣播 實現次發送所有組客戶端都能接收到

send all users 代碼示例 proto 次數 不可 的人 ssa 原文作者:aircraft 原文鏈接:https://www.cnblogs.com/DOMLX/p/9614288.html 一.多播 鍥子:有這麽一種情況,網絡電臺可能需要同時向成

LINUXsocket實現伺服器與多客戶端通訊(

一直對網路方面的技術比較感興趣,有時間就學習學習。雖然現在很多高階語言都已將網路程式設計部分做了封裝處理,使之使用更加方便,但是學習基礎原理,還是一個程式設計師必須要做的。 linux下的socket程式設計原理,網路上已經有大把的詳細說明,這裡不做說明,程式碼中已有簡單註釋。 具體方法,有

linuxsocket程式設計實現一個伺服器連線多個客戶端

使用socekt通訊一般步驟     1)伺服器端:socker()建立套接字,繫結(bind)並