Tôi biết có khá nhiều câu hỏi SE về vấn đề này và tôi tin rằng tôi đã đọc nhiều câu hỏi như vậy trước khi đến thời điểm này.
Theo "phía máy chủ TIME_WAIT
", ý tôi là trạng thái của cặp ổ cắm phía máy chủ đã đóng () được khởi tạo ở phía máy chủ.
Tôi thường thấy những tuyên bố này nghe có vẻ mâu thuẫn với tôi:
- Phía máy chủ
TIME_WAIT
là vô hại - Bạn nên thiết kế các ứng dụng mạng của mình để có các máy khách khởi tạo close (), do đó, ứng dụng khách phải chịu
TIME_WAIT
Lý do tôi thấy mâu thuẫn này là vì TIME_WAIT
trên máy khách có thể là một vấn đề - máy khách có thể chạy hết các cổng có sẵn, vì vậy, về bản chất, chúng tôi khuyên bạn nên chuyển gánh nặng TIME_WAIT
sang phía máy khách, nơi có thể gặp sự cố, từ phía máy chủ không phải là vấn đề.
Phía khách hàng TIME_WAIT
tất nhiên chỉ là một vấn đề đối với số lượng hạn chế các trường hợp sử dụng. Hầu hết các giải pháp máy chủ-máy khách sẽ liên quan đến một máy chủ và nhiều máy khách, khách hàng thường không xử lý được khối lượng kết nối đủ lớn để nó trở thành một vấn đề và ngay cả khi chúng xảy ra, vẫn có một số khuyến nghị để "hoàn toàn" ( trái ngược SO_LINGER
với thời gian chờ 0 hoặc can thiệp với tcp_tw sysctls) chiến đấu phía khách hàng TIME_WAIT
bằng cách tránh tạo quá nhiều kết nối quá nhanh. Nhưng điều đó không phải lúc nào cũng khả thi, ví dụ như đối với lớp ứng dụng như:
- hệ thống giám sát
- máy phát điện tải
- proxy
Mặt khác, tôi thậm chí không hiểu phía máy chủ TIME_WAIT
hữu ích như thế nào . Lý do TIME_WAIT
thậm chí còn có, là bởi vì nó ngăn chặn việc bơm TCP
các mảnh cũ vào dòng mà họ không còn thuộc về. Đối với phía khách hàng TIME_WAIT
, việc này được thực hiện bằng cách đơn giản là không thể tạo kết nối với cùng ip:port
các cặp mà kết nối cũ này có thể có (các cặp đã sử dụng bị khóa bởi TIME_WAIT
). Nhưng đối với phía máy chủ, điều này không thể được ngăn chặn vì địa chỉ cục bộ sẽ có cổng chấp nhận và luôn luôn giống nhau và máy chủ không thể (AFAIK, tôi chỉ có bằng chứng thực nghiệm) từ chối kết nối đơn giản vì một đồng đẳng đến sẽ tạo ra cặp địa chỉ giống nhau đã tồn tại trong bảng ổ cắm.
Tôi đã viết một chương trình cho thấy TIME-WAIT phía máy chủ bị bỏ qua. Hơn nữa, vì thử nghiệm đã được thực hiện vào ngày 127.0.0.1, hạt nhân phải có một bit đặc biệt thậm chí cho nó biết đó là phía máy chủ hay phía máy khách (vì nếu không thì bộ dữ liệu sẽ giống nhau).
Nguồn: http://pastebin.com/5PWjkjEf , đã thử nghiệm trên Fedora 22, cấu hình mạng mặc định.
$ gcc -o rtest rtest.c -lpthread
$ ./rtest 44400 s # will do server-side close
Will initiate server close
... iterates ~20 times successfully
^C
$ ss -a|grep 44400
tcp TIME-WAIT 0 0 127.0.0.1:44400 127.0.0.1:44401
$ ./rtest 44500 c # will do client-side close
Will initiate client close
... runs once and then
connecting...
connect: Cannot assign requested address
Vì vậy, đối với phía máy chủ TIME_WAIT
, các kết nối trên cùng một cặp cổng chính xác có thể được thiết lập lại ngay lập tức và thành công và đối với phía máy khách TIME-WAIT
, ở lần lặp thứ hai connect()
đã thất bại một cách chính đáng
Tóm lại, câu hỏi có hai phần:
- Có phải phía máy chủ
TIME_WAIT
thực sự không làm gì cả, và chỉ còn lại như vậy bởi vìRFC
yêu cầu nó phải làm? - Là lý do đề xuất cho khách hàng để bắt đầu close () vì máy chủ
TIME_WAIT
là vô dụng?
TIME_WAIT
.