1.connect函數響應中斷返回後仍然回到函數的調用。
實踐證實,對於一個非阻塞的socket,若是在調用connect函數時,若是發生中斷,這函數響應中斷,但當中斷返回時,繼續connect函數的調用,直到connect超時失敗或接收到錯誤ICMP包或鏈接成功服務器
2.accept()
若是偵聽進程是非阻塞模式工做,當調用accept()函數接收來自客戶端的請求後,返回的socket套接字,默認爲阻塞的工做模式。網絡
1、阻塞模型
可能發生阻塞的套接口調用分爲四種:
1>.輸入操做:read、readv、recv、recvfrom和recvmsg函數
2>.輸出操做:write、writev、send、sendto和sendmsg函數
3>.接收外來鏈接:accept()函數
4>.初始化外出的鏈接:connect()函數數據結構
2、I/O模型
1.阻塞I/O
2.非阻塞I/O
3.I/O複用(select函數)
4.信號驅動I/O(SIGIO)
5.異步I/O異步
3、I/O複用模型的應用場合
1.當客戶處理多個描述字時(通常是交互式輸入和網絡套接口),必須使用I/O複用。
2.一個客戶同時處理多個套接口
3.若是一個TCP服務器既要處理偵聽套接口,又要處理已鏈接套接口,通常也要用到I/O複用。
4.若是一個服務器既要處理TCP,又要處理UDP,通常也要使用I/O複用。
5.若是一個服務器要處理多個服務或者多個協議(inetd守護進程)。socket
4、拒絕服務型攻擊
服務器某一個時刻阻塞於只處理單個客戶,而不能處理其餘客戶的需求,這就致使了拒絕服務型攻擊,可能的解決辦法是:(a)使用非阻塞I/O模型;(b)讓 每一個客戶由單獨的控制線程提供服務(例如,建立子進程或線程來爲每一個客戶提供服務);(c)對I/O操做設置超時。函數
5、connect()函數
1.阻塞模式
客戶端調用connect()函數將激發TCP的三路握手過程,但僅在鏈接創建成功或出錯時才返回。返回的錯誤可能有如下幾種狀況:
1>.若是TCP客戶端沒有接收到SYN分節的響應,則返回ETIMEDOUT,阻塞模式的超時時間在75秒(4.4BSD內核)到幾分鐘之間。
2>.若是對客戶的SYN的響應時RST,則代表該服務器主機在咱們指定的端口上沒有進程在等待與之鏈接(例如服務器進程也許沒有啓動),這稱爲硬錯,客戶一接收到RST,立刻就返回錯誤ECONNREFUSED.
3>.若是某客戶發出的SYN在中間的路由器上引起了一個目的地不可達ICMP錯誤,屢次嘗試發送失敗後返回錯誤號爲EHOSTUNREACH或ENETUNREACH.spa
附加:產生RST的三種狀況,一是SYN到達某端口但此端口上沒有正在偵聽的服務器、二是TCP想取消一個已有鏈接、三是TCP接收了一個根本不存在的鏈接上的分節。線程
2.非阻塞模式
採用非阻塞的工做模式要考慮一下兩種狀況:
1>.若是是鏈接本機,則調用connect()函數會馬上創建。
2>.若是服務器是網絡中的用戶,則調用connect()函數須要從幾個毫秒的局域網到幾百毫秒或幾秒的廣域網。而且函數會馬上返回EINPROCESS錯誤,但TCP通訊的三路握手過程正在進行,因此可使用select函數來檢查這個鏈接是否創建成功。
源自Berkeley的實現有兩條與select函數和非阻塞相關的規則:
1>.當鏈接成功創建時,描述字變成可寫。
2>.當鏈接創建出錯時,描述字變成便可讀又可寫。code
6、accept()函數
1.阻塞模式
若是在一個阻塞套接口上調用accept()函數,並且沒有新的鏈接,進程會進入睡眠狀態。orm
2.非阻塞模式
若是在一個非阻塞套接口上調用accept()函數,並且沒有新的鏈接,將返回EWOULDBLOCK錯誤。
3.一種非阻塞模式例子的問題及解決辦法
問題描述:在服務器端偵聽套接口採用阻塞的方式工做,而且使用select檢測是否有已經創建起的鏈接,若是有則調用accept()函數接收該鏈接,問 題是若是客戶端首先調用connect()函數鏈接服務器後馬上又調用close()函數關閉該鏈接,而在服務器端,在select()函數返回和調用 accept()函數之間,接收到客戶端的斷開,則會刪除該套接口在已鏈接套接口中的內容,因此服務器將會阻塞在accept()函數,直到有客戶鏈接才 返回。
解決辦法:(1).若是用select來獲知什麼時候有鏈接已就緒能夠accept時,老是把偵聽套接口置爲非阻塞,同時(2).在後面的accept調用中 忽略如下錯誤:EWOULDBLOCK(Berkeley的實如今客戶放棄鏈接時出現的錯誤)、ECONNABORTED(Posix.1g的實如今客戶 放棄鏈接時出現的錯誤)、EPROTO(SVR4的實如今客戶放棄鏈接時出現的錯誤)和EINTR(若是信號被捕獲)。
7、select()函數
select()函數準備好讀的條件:
1>.套接口有數據可讀
2>.該鏈接的讀這一半關閉(也就是接收了FIN的TCP鏈接)。對這樣的套接口進行讀操做將不阻塞並返回0(也就是返回EOF)。
3>.該套接口是一個偵聽套接口且已完成的鏈接數不爲0。
4>.其上有一個套接口錯誤待處理,對這樣的套接口的讀操做將不阻塞並返回-1,並設置errno,能夠經過設置SO_ERROR選項調用getsockopt函數得到。
select()函數準備好寫的條件:
1>.套接口有可用於寫的空間。
2>.該鏈接的寫這一半關閉,對這樣的套接口進行寫操做將產生SIGPIPE信號。
3>.該套接口使用非阻塞的方式connect創建鏈接,而且鏈接已經異步創建,或則connect已經以失敗了結。
4>.其上有一個套接口錯誤待處理。
8、read()函數和recv函數
read()函數返回值表明的意義:
1>.若是對方TCP發送數據,則套接口就變爲可讀且read返回大於0的值(即數據的字節數)。
2>.若是對方TCP發送一個FIN(對方進程終止),套接口就變爲可讀且read返回0(文件結束)。
3>.若是對方TCP發送一個RST(對方主機崩潰並從新啓動),套接口就變成可讀且read返回-1,返回的錯誤號errno爲ECONNRESET。
9、write()函數和send函數
若是向一個接收了FIN的套接字進行寫操做是可行的,但若是向一個接受了RST的套接字進行寫操做則是致命的,內核會向該進程發送一個SIGPIPE信號,返回EPIPO,該錯誤類型默認爲終止進程。
SIGPIPE信號
向一個接受了RST的套接字進行寫操做時,內核會向該進程發送一個SIGPIPE信號,該信號的缺省行爲是終止進程,所以進程必須捕獲它以避免被不情願的終止。
五、 Linux中Socket的數據結構
(1)
struct sockaddr { //用於存儲套接字地址 unsigned short sa_family;//地址類型 char sa_data[14]; //14字節的協議地址 };
(2)
struct sockaddr_in{ //in 表明internet short int sin_family; //internet協議族 unsigned short int sin_port;//端口號,必須是網絡字節順序 struct in_addr sin_addr;//internet地址,必須是網絡字節順序 unsigned char sin_zero;//添0(和struct sockaddr同樣大小 };
(3)
struct in_addr{ unsigned long s_addr; };