SO_LINGER選項用來(lái)設置延遲關(guān)閉的時(shí)間,等待套接字發(fā)送緩沖區中的數據發(fā)送完成。沒(méi)有設置該選項時(shí),在調用close()后,在發(fā)送完FIN后會(huì )立即進(jìn)行一些清理工作并返回。如果設置了SO_LINGER選項,并且等待時(shí)間為正值,則在清理之前會(huì )等待一段時(shí)間。
以調用close()主動(dòng)關(guān)閉為例,在發(fā)送完FIN包后,會(huì )進(jìn)入FIN_WAIT_1狀態(tài)。如果沒(méi)有延遲關(guān)閉(即設置SO_LINGER選項),在調用tcp_send_fin()發(fā)送FIN后會(huì )立即調用sock_orphan()將sock結構從進(jìn)程上下文中分離。分離后,用戶(hù)層進(jìn)程不會(huì )再接收到套接字的讀寫(xiě)事件,也不知道套接字發(fā)送緩沖區中的數據是否被對端接收。如果設置了SO_LINGER選項,并且等待時(shí)間為大于0的值,會(huì )等待套接字的狀態(tài)從FIN_WAIT_1遷移到FIN_WAIT_2狀態(tài)。我們知道套接字進(jìn)入FIN_WAIT_2狀態(tài)是在發(fā)送的FIN包被確認后,而FIN包肯定是在發(fā)送緩沖區中的最后一個(gè)字節,所以FIN包的確認就表明發(fā)送緩沖區中的數據已經(jīng)全部被接收。當然,如果等待超過(guò)SO_LINGER選項設置的時(shí)間后,還是沒(méi)有收到FIN的確認,則繼續進(jìn)行正常的清理工作,Linux下也沒(méi)有返回錯誤。從這里看來(lái),SO_LINGER選項的作用是等待發(fā)送緩沖區中的數據發(fā)送完成,但是并不保證發(fā)送緩沖區中的數據一定被對端接收(對端宕機或線(xiàn)路問(wèn)題),只是說(shuō)會(huì )等待一段時(shí)間讓這個(gè)過(guò)程完成。如果在等待的這段時(shí)間里接收到了帶數據的包,還是會(huì )給對端發(fā)送RST包,并且會(huì )reset掉套接字,因為此時(shí)已經(jīng)關(guān)閉了接收通道。
在使用這個(gè)選項來(lái)延遲關(guān)閉連接的時(shí)候有兩個(gè)地方需要注意:
1. 進(jìn)程會(huì )睡眠,直到狀態(tài)不為FIN_WAIT_1、CLOSING、LAST_ACK(也就是接收到對FIN的ACK包),或者等待超時(shí)
2. 在等待的過(guò)程中如果接收到帶數據的包還是會(huì )發(fā)送RST包
3.消耗更多的額外資源
TCP協(xié)議是一個(gè)通用的傳輸層協(xié)議,不關(guān)心上層具體的業(yè)務(wù),如果要延遲關(guān)閉連接,最好是結合自己的業(yè)務(wù)和場(chǎng)景自己來(lái)管理,不要依賴(lài)這個(gè)選項。nginx的延遲關(guān)閉就是自己來(lái)管理的,覺(jué)得要比直接使用SO_LINGER選項好一些,并且不會(huì )導致進(jìn)程阻塞。 ngxin在發(fā)送錯誤信息后,會(huì )等待一段時(shí)間,讓用戶(hù)把所有的數據都發(fā)送完。超過(guò)等待時(shí)間后,會(huì )直接關(guān)閉連接。通過(guò)lingering_close,nginx可以保持更好的客戶(hù)端兼容性,避免客戶(hù)端被reset掉。
SO_LINGER還有一個(gè)作用就是用來(lái)減少TIME_WAIT套接字的數量。在設置SO_LINGER選項時(shí),指定等待時(shí)間為0,此時(shí)調用主動(dòng)關(guān)閉時(shí)不會(huì )發(fā)送FIN來(lái)結束連接,而是直接將連接設置為CLOSE狀態(tài),清除套接字中的發(fā)送和接收緩沖區,直接對對端發(fā)送RST包。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請
點(diǎn)擊舉報。