socket api 存在一批覈心接口,而這一批覈心接口就是幾個看似簡單的函數,儘管實際上這些函數沒有一個是簡單。connect 函數就是這些核心接口中的一個函數,它完成主動鏈接的過程。 linux
connect 函數的功能對於 TCP 來講就是完成面向鏈接的協議的鏈接過程,它的函數原型:
linux下 windows
#include<sys/socket.h>
#include<sys/types.h>
int connect(int sockfd, const struct sockaddr* server_addr, socklen_t addrlen)
windows下
int connect(
SOCKET s, // 沒綁定套接口描述字
const struct sockaddr FAR *name, // 目標地址指針,目標地址中必須包含IP和端口信息。
int namelen // name的長度
);
面向鏈接的協議,在創建鏈接的時候總會有一方先發送數據(SYN),那麼誰調用了 connect 誰就是先發送數據的一方。如此理解 connect 三個參數就容易了。我必需指定數據發送的目的地址,同時也必需指定數據從哪裏發送,這正好是 connect 的前兩個參數,而第三個參數是爲第二個參數服務的。
參數
sockfd
指定數據發送的套接字,解決從哪裏發送的問題。內核須要維護大量 I/O 通道,因此用戶必需經過這個參數告訴內核從哪一個 I/O 通道(此處就是從哪一個 socket 接口)中發送數據。
參數
server_addr
指定數據發送的目的地,也就是服務器端的地址。這裏服務器是針對 connect 說的,由於 connect 是主動鏈接的一方調用的,因此相應的要存在一個被鏈接的一方,被動鏈接的一方須要調用 listen 以接受 connect 的鏈接請求,如此被動鏈接的一方就是服務器了。
參數
addrlen
指定 server_addr 結構體的長度。咱們知道系統中存在大量的地址結構,但 socket 接口只是經過一個統一的結構來指定參數類型,因此須要指定一個長度,以使內核在進行參數複製的時候有個界限。
返回值:沒有錯誤發生,返回0;不然返回 SOCKET_ERROR(-1) 。 後端
==================== api
與全部的 socket 網絡接口同樣,connect 總會在某個時候可能失敗,此時它會返回 -1 ,相應的 errno 會被設置,用戶可能經過這個值肯定是哪一個錯誤。常見的錯誤有對方主機不可達或者超時錯誤,也能夠是對方主機沒有相應的進程在對應端口等待。 服務器
connect 函數可用於
面向鏈接套接字,
也可用於
無鏈接套接字
。
無鏈接套接字
:對於無鏈接的套接字 (SOCK_DGRAM) ,該套接字與目標地址之間創建默認的對應關係,且在本地保存了對端的地址,這樣後續的讀寫操做能夠默認以鏈接的對端爲操做對象,網絡數據交互發生時能夠直接使用 send ,而不是用 sendto 來向該地址發送數據;內核會丟棄全部發送給該套接字的源地址不是 connect 地址的報文。再次調用 connect 函數,若此時 name 和 namelen 兩個參數均爲空指針,就會將該套接字恢復爲未鏈接狀態,再調用 send 函數,系統會提示 WSAENOTCONN 錯誤碼。
面向鏈接套接字
:面向鏈接的套接字 (SOCK_STREAM) ,函數 connect 會引發調用端主動進行 TCP 的三次握手過程。結果一般是成功鏈接、WSAETIMEDOUT (屢次發送SYN報文,始終未收到回覆)、WSAECONNREFUSED (目標主機返回 RST) 等。
當對端機器 crash 或者網絡鏈接被斷開(好比路由器不工做,網線斷開等),此時發送數據給對端而後,讀取本端 socket 會返回 ETIMEDOUT 或者 EHOSTUNREACH 或者 ENETUNREACH (後兩個是中間路由器判斷服務器主機不可達的狀況)。
當對端機器 crash 以後又從新啓動,而後客戶端再向原來的鏈接發送數據,由於服務器端已經沒有原來的鏈接信息,此時服務器端回送 RST 給客戶端,此時客戶端讀本地端口返回 ECONNRESET 錯誤。
當服務器所在的進程正常或者異常關閉時,會對全部打開的文件描述符進行 close ,所以對於鏈接的 socket 描述符則會向對端發送 FIN 分節進行正常關閉流程。對端在收到 FIN 以後端口變得可讀,此時讀取端口會返回 0 表示到了文件結尾(對端不會再發送數據)。
當一端收到 RST 致使讀取 socket 返回 ECONNRESET ,此時若是再次調用 write 發送數據給對端則觸發 SIGPIPE 信號,信號默認終止進程,若是忽略此信號或者從 SIGPIPE 的信號處理程序返回則 write 出錯返回 EPIPE 。
=================================
=====
1) Broken PIPE 的字面意思是「管道破裂」。Broken PIPE 產生的緣由是該管道的讀端被關閉。
2) Broken PIPE 常常發生在 Client 端經過 Socket 發送信息到 Server 端後,就關閉當前 Socket , 以後 Server 端回覆信息給 Client 端時。
3) 發生 Broken PIPE 錯誤時,調用寫的進程會收到 SIGPIPE 信號,默認動做是致使當前進程終止。
4) Broken PIPE 最直接的意思是:寫入端出現的時候,PIPE 的另外一端卻休息或退出了,所以形成沒有及時取走管道中的數據,從而系統異常退出。
Client 端經過 PIPE 發送信息到 Server 端後,就關閉 Client 端 Socket , 這時 Server 端返回信息給 Client 端時就會產生 Broken PIPE 信號。
====================================== 網絡
能夠看出,只有當本地端口主動發送消息給對端時,才能檢測出鏈接異常中斷的狀況,搭配 select 進行多路分離的時候,socket 收到 RST 或者 FIN 時候,select 返回可讀(心跳消息就是用於檢測鏈接的狀態)。也可使用 socket 的 KEEPLIVE 選項,依賴 socket 自己偵測 socket 鏈接異常中斷的狀況。
錯誤信息:
EACCES, EPERM:用戶試圖在套接字廣播標誌沒有設置的狀況下鏈接廣播地址或因爲防火牆策略致使鏈接失敗。
EADDRINUSE:本地地址處於使用狀態。
EAFNOSUPPORT:參數 serv_add 中的地址非法。
EAGAIN:沒有足夠空閒的本地端口。
EALREADY:套接字爲非阻塞套接字,而且原來的鏈接請求還未完成。
EBADF:非法的文件描述符。
ECONNREFUSED:遠程地址並無處於監聽狀態。
EFAULT:指向套接字結構體的地址非法。
EINPROGRESS:套接字爲非阻塞套接字,且鏈接請求沒有當即完成。
EINTR:系統調用的執行因爲捕獲中斷而停止。
EISCONN:已經鏈接到該套接字。
ENETUNREACH:網絡不可到達。
ENOTSOCK:文件描述符不與套接字相關。
ETIMEDOUT:鏈接超時。 socket