天天看點

linux網絡程式設計-----非阻塞connect

libevent在内部由于使用io多路複用函數進行的事件監控,是以它所有的io讀寫操作都是非阻塞的,換句話說,libevent提供的接口函數evconnlistener_new_bind()和bufferevent_socket_connect()在内部使用socket建立套接字,會預設将其變為非阻塞(使用fcntl可以實作)。

比較特殊的就是用戶端的connect函數,因為套接字變為非阻塞,是以connect會立即傳回,這就可能出現以下三種情況

  • 連接配接立即建立,傳回0
  • 正在進行三路握手,傳回-1,errno設定為EINPROGRESS
  • 連接配接失敗,傳回-1,errno不為EINPROGRESS

非阻塞的connect可以節省三路握手的時間,可以運作其它的任務,不需要等待三路握手完成。

是以判斷什麼時候連接配接建立完成是很重要的,判斷的依據是套接字的可讀/可寫狀态

  • 當連接配接成功建立時,描述符變為可寫
  • 當連接配接建立遇到錯誤時,描述符變為既可讀又可寫

這兩個規則很好了解,

  • 當連接配接成功建立,tcp的緩沖區為空,用戶端就可以使用send/write等io函數向套接字描述符寫入資料,就是說描述符變為可寫
  • 當連接配接建立失敗,tcp的緩沖區仍然可寫,但是因為出現錯誤,是以緩沖區中存在着連接配接錯誤資訊,是以既可讀又可寫

有以下幾種方法可以達到對connect連接配接的判斷

  • 使用select對用戶端套接字進行監聽,同時設定逾時時長。這種方法主要用于減少connect預設的逾時時長,當select傳回後,可以判斷套接字描述符是否處在讀/寫事件集中。
  • 既然libevent是統一事件源,是以連接配接的建立也是一個事件,将套接字描述符添加到event監控中,當可讀/可寫時就可以判斷連接配接情況
  • 上述兩種方法都可以在io多路複用函數傳回後通過getsockopt擷取套接字SO_ERROR選項,當結果為0時表示連接配接建立,否則失敗
/* 結果存入error中 */
getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);
           

繼續閱讀