Tôi đã nghe nói về tính năng giữ nguyên HTTP nhưng hiện tại tôi muốn mở kết nối ổ cắm với máy chủ từ xa.
Bây giờ kết nối socket này sẽ vẫn mở mãi mãi hay có giới hạn thời gian chờ liên quan đến nó tương tự như HTTP keep-live?
Tôi đã nghe nói về tính năng giữ nguyên HTTP nhưng hiện tại tôi muốn mở kết nối ổ cắm với máy chủ từ xa.
Bây giờ kết nối socket này sẽ vẫn mở mãi mãi hay có giới hạn thời gian chờ liên quan đến nó tương tự như HTTP keep-live?
Câu trả lời:
Các ổ cắm TCP vẫn mở cho đến khi chúng được đóng lại.
Điều đó nói rằng, rất khó để phát hiện một kết nối bị hỏng (bị hỏng, như trong bộ định tuyến bị chết, v.v., trái ngược với đóng) mà không thực sự gửi dữ liệu, vì vậy hầu hết các ứng dụng thường thực hiện một số loại phản ứng bóng bàn chỉ để đảm bảo kết nối vẫn thực sự tồn tại.
Bây giờ kết nối socket này sẽ vẫn mở mãi mãi hay có giới hạn thời gian chờ liên quan đến nó tương tự như HTTP keep-live?
Câu trả lời ngắn gọn là không, nó sẽ không mở mãi mãi, nó có thể sẽ hết sau vài giờ. Do đó có có là một thời gian chờ và nó được thực thi thông qua giao thức TCP Giữ-Alive .
Nếu bạn muốn định cấu hình thời gian chờ Keep-Alive trên máy của mình, hãy xem phần "Thay đổi thời gian chờ TCP" bên dưới. Nếu không, hãy đọc qua phần còn lại của câu trả lời để tìm hiểu cách hoạt động của TCP Keep-Alive.
Kết nối TCP bao gồm hai ổ cắm, một ở mỗi đầu của kết nối. Khi một bên muốn ngắt kết nối, nó sẽ gửi một RST
gói tin mà bên kia thừa nhận và cả hai đều đóng các ổ cắm của họ.
Tuy nhiên, cho đến khi điều đó xảy ra, cả hai bên sẽ giữ ổ cắm của họ mở vô thời hạn. Điều này mở ra khả năng một bên có thể đóng ổ cắm của họ, cố ý hoặc do lỗi nào đó mà không thông báo cho đầu kia biết RST
. Để phát hiện tình huống này và đóng các kết nối cũ, quy trình TCP Keep Alive được sử dụng.
Có ba thuộc tính có thể định cấu hình xác định cách hoạt động của Keep-Alives. Trên Linux, chúng là 1 :
tcp_keepalive_time
tcp_keepalive_probes
tcp_keepalive_intvl
Quá trình hoạt động như sau:
tcp_keepalive_time
vài giây, hãy gửi một ACK
gói tin trống . 1ACK
của riêng nó không?
tcp_keepalive_intvl
vài giây, sau đó gửi mộtACK
ACK
đầu dò đã được gửi bằng nhau tcp_keepalive_probes
.RST
và ngắt kết nối.Quá trình này được kích hoạt theo mặc định trên hầu hết các hệ điều hành và do đó các kết nối TCP đã chết thường xuyên bị loại bỏ khi đầu kia không phản hồi trong 2 giờ 11 phút (7200 giây + 75 * 9 giây).
Vì quá trình này không bắt đầu cho đến khi kết nối không hoạt động trong hai giờ theo mặc định, các kết nối TCP cũ có thể tồn tại trong một thời gian rất dài trước khi bị loại bỏ. Điều này có thể đặc biệt có hại cho các kết nối đắt tiền như kết nối cơ sở dữ liệu.
Theo RFC 1122 4.2.3.6 , phản hồi và / hoặc chuyển tiếp các gói TCP Keep-Alive là tùy chọn :
Người triển khai CÓ THỂ bao gồm "keep-alives" trong triển khai TCP của họ, mặc dù thực tiễn này không được chấp nhận trên toàn cầu. Nếu giữ bí danh được bao gồm, ứng dụng PHẢI có thể bật hoặc tắt chúng cho mỗi kết nối TCP và chúng PHẢI mặc định là tắt.
...
Điều cực kỳ quan trọng cần nhớ là các đoạn ACK không chứa dữ liệu sẽ không được TCP truyền đi một cách đáng tin cậy.
Lý do là các gói Keep-Alive không chứa dữ liệu và không hoàn toàn cần thiết và có nguy cơ gây tắc nghẽn các ống của mạng xen kẽ nếu sử dụng quá mức.
Tuy nhiên , trong thực tế , kinh nghiệm của tôi là mối quan tâm này đã giảm dần theo thời gian khi băng thông ngày càng rẻ hơn; và do đó các gói Keep-Alive thường không bị loại bỏ. Ví dụ: tài liệu Amazon EC2 đưa ra sự chứng thực gián tiếp của Keep-Alive, vì vậy nếu bạn đang lưu trữ bằng AWS, bạn có thể an toàn khi dựa vào Keep-Alive, nhưng số dặm của bạn có thể thay đổi.
Thật không may vì các kết nối TCP được quản lý ở cấp hệ điều hành, Java không hỗ trợ định cấu hình thời gian chờ ở cấp độ mỗi ổ cắm chẳng hạn như trong java.net.Socket
. Tôi đã tìm thấy một số nỗ lực 3 sử dụng Java Native Interface (JNI) để tạo các ổ cắm Java gọi mã gốc để định cấu hình các tùy chọn này, nhưng dường như không có nỗ lực nào được cộng đồng chấp nhận hoặc hỗ trợ rộng rãi.
Thay vào đó, bạn có thể buộc phải áp dụng cấu hình của mình cho toàn bộ hệ điều hành. Cần biết rằng cấu hình này sẽ ảnh hưởng đến tất cả các kết nối TCP đang chạy trên toàn bộ hệ thống.
Bạn có thể tìm thấy cài đặt TCP Keep-Alive được định cấu hình hiện tại trong
/proc/sys/net/ipv4/tcp_keepalive_time
/proc/sys/net/ipv4/tcp_keepalive_probes
/proc/sys/net/ipv4/tcp_keepalive_intvl
Bạn có thể cập nhật bất kỳ cái nào trong số này như vậy:
# Send first Keep-Alive packet when a TCP socket has been idle for 3 minutes
$ echo 180 > /proc/sys/net/ipv4/tcp_keepalive_time
# Send three Keep-Alive probes...
$ echo 3 > /proc/sys/net/ipv4/tcp_keepalive_probes
# ... spaced 10 seconds apart.
$ echo 10 > /proc/sys/net/ipv4/tcp_keepalive_intvl
Những thay đổi như vậy sẽ không tồn tại khi khởi động lại. Để thực hiện các thay đổi liên tục, hãy sử dụng sysctl
:
sysctl -w net.ipv4.tcp_keepalive_time=180 net.ipv4.tcp_keepalive_probes=3 net.ipv4.tcp_keepalive_intvl=10
Có thể xem các cài đặt được định cấu hình hiện tại bằng sysctl
:
$ sysctl net.inet.tcp | grep -E "keepidle|keepintvl|keepcnt"
net.inet.tcp.keepidle: 7200000
net.inet.tcp.keepintvl: 75000
net.inet.tcp.keepcnt: 8
Đáng chú ý, Mac OS X định nghĩa keepidle
và keepintvl
theo đơn vị mili giây so với Linux sử dụng giây.
Các thuộc tính có thể được đặt với các thuộc tính sysctl
này sẽ duy trì các cài đặt này khi khởi động lại:
sysctl -w net.inet.tcp.keepidle=180000 net.inet.tcp.keepcnt=3 net.inet.tcp.keepintvl=10000
Ngoài ra, bạn có thể thêm chúng vào /etc/sysctl.conf
(tạo tệp nếu nó không tồn tại).
$ cat /etc/sysctl.conf
net.inet.tcp.keepidle=180000
net.inet.tcp.keepintvl=10000
net.inet.tcp.keepcnt=3
Tôi không có máy Windows để xác nhận, nhưng bạn nên tìm cài đặt TCP Keep-Alive tương ứng trong sổ đăng ký tại
\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters
Chú thích
1. Xem man tcp
để biết thêm thông tin.
2. Gói này thường được gọi là gói "Keep-Alive", nhưng trong đặc tả TCP nó chỉ là một ACK
gói thông thường . Các ứng dụng như Wireshark có thể gắn nhãn nó là một gói "Keep-Alive" bằng cách phân tích tổng hợp chuỗi và số xác nhận mà nó chứa liên quan đến các giao tiếp trước đó trên socket.
3. Một số ví dụ tôi tìm thấy từ tìm kiếm cơ bản của Google là lucwilliams / JavaLinuxNet và flonatel / libdontdie .
$ no -a | grep tcp_keep
lệnh.
Bạn đang tìm kiếm tùy chọn ổ cắm SO_KEEPALIVE.
Các Java Socket API phơi bày "giữ-sống" cho các ứng dụng thông qua setKeepAlive
và getKeepAlive
phương pháp.
CHỈNH SỬA: SO_KEEPALIVE được triển khai trong ngăn xếp giao thức mạng hệ điều hành mà không gửi bất kỳ dữ liệu "thực" nào. Khoảng thời gian tồn tại phụ thuộc vào hệ điều hành và có thể được điều chỉnh thông qua một tham số hạt nhân.
Vì không có dữ liệu nào được gửi đi, SO_KEEPALIVE chỉ có thể kiểm tra tính hoạt động của kết nối mạng, không phải về tính hoạt động của dịch vụ mà ổ cắm được kết nối. Để kiểm tra phần sau, bạn cần triển khai một cái gì đó liên quan đến việc gửi tin nhắn đến máy chủ và nhận phản hồi.
TCP keepalive và HTTP keepalive là những khái niệm rất khác nhau. Trong TCP, keepalive là gói quản trị được gửi để phát hiện kết nối cũ. Trong HTTP, keepalive có nghĩa là trạng thái kết nối liên tục.
Đây là từ đặc tả TCP,
Các gói còn tồn tại PHẢI chỉ được gửi khi không nhận được dữ liệu hoặc gói thông báo cho kết nối trong một khoảng thời gian. Khoảng thời gian này PHẢI được định cấu hình và PHẢI mặc định không ít hơn hai giờ.
Như bạn có thể thấy, khoảng thời gian lưu giữ mặc định của TCP quá dài đối với hầu hết các ứng dụng. Bạn có thể phải thêm keepalive trong giao thức ứng dụng của mình.
HTTP/1.0
mỗi yêu cầu / phản hồi, cần phải kết nối lại với máy chủ. Vì HTTP/1.1
họ đã giới thiệu một Keep-Alive
tiêu đề có thể được sử dụng để kích hoạt máy chủ không ngắt kết nối sau khi nó được xử lý xong phản hồi để tạo điều kiện yêu cầu thêm tệp và cho phép 'pipelining'; gửi nhiều yêu cầu sau đó đợi tất cả dữ liệu quay trở lại.
Nếu bạn đứng sau một NAT giả mạo (như hầu hết người dùng gia đình ngày nay), thì có một nhóm hạn chế các cổng bên ngoài và những cổng này phải được chia sẻ giữa các kết nối TCP. Do đó, các NAT giả mạo có xu hướng cho rằng một kết nối đã bị chấm dứt nếu không có dữ liệu nào được gửi trong một khoảng thời gian nhất định.
Sự cố này và các vấn đề khác như vậy (ở bất kỳ vị trí nào giữa hai điểm cuối) có thể có nghĩa là kết nối sẽ không còn "hoạt động" nếu bạn cố gắng gửi dữ liệu sau một khoảng thời gian không hoạt động hợp lý. Tuy nhiên, bạn có thể không phát hiện ra điều này cho đến khi bạn cố gắng gửi dữ liệu.
Việc sử dụng keepalives vừa làm giảm nguy cơ kết nối bị gián đoạn ở một nơi nào đó dưới đường truyền, vừa giúp bạn phát hiện ra kết nối bị hỏng sớm hơn.
Dưới đây là một số tài liệu bổ sung về lưu giữ giải thích nó một cách chi tiết hơn nhiều.
http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO
Vì Java không cho phép bạn kiểm soát thời gian lưu giữ thực tế, bạn có thể sử dụng các ví dụ để thay đổi chúng nếu bạn đang sử dụng nhân Linux (hoặc hệ điều hành dựa trên proc).
Trong JAVA Socket - Các kết nối TCP được quản lý ở cấp độ hệ điều hành, java.net.Socket không cung cấp bất kỳ chức năng tích hợp nào để đặt thời gian chờ cho gói lưu giữ ở cấp độ mỗi ổ cắm. Nhưng chúng tôi có thể bật tùy chọn keepalive cho java socket nhưng phải mất 2 giờ 11 phút (7200 giây) theo mặc định để xử lý sau khi kết nối tcp cũ. Kết nối nguyên nhân này sẽ tồn tại trong một thời gian rất dài trước khi thanh lọc. Vì vậy, chúng tôi đã tìm thấy một số giải pháp để sử dụng Java Native Interface (JNI) gọi mã gốc (c ++) để định cấu hình các tùy chọn này.
**** Hệ điều hành Windows ****
Trong hệ điều hành windows, keepalive_time & keepalive_intvl có thể được định cấu hình nhưng không thể thay đổi tcp_keepalive_probes. Theo mặc định, khi khởi tạo TCP socket sẽ đặt thời gian chờ duy trì thành 2 giờ và khoảng thời gian giữ sống là 1 giây. Giá trị mặc định trên toàn hệ thống của thời gian chờ duy trì có thể kiểm soát được thông qua cài đặt đăng ký KeepAliveTime, giá trị này nhận giá trị tính bằng mili giây.
Trên Windows Vista trở lên, số lượng đầu dò còn tồn tại (truyền lại dữ liệu) được đặt thành 10 và không thể thay đổi.
Trên Windows Server 2003, Windows XP và Windows 2000, cài đặt mặc định cho số đầu dò còn sống là 5. Có thể kiểm soát được số lượng đầu dò còn sống. Đối với windows, thư viện Winsock IOCTLs được sử dụng để cấu hình các tham số tcp-keepalive.
int WSAIoctl (SocketFD, // bộ mô tả nhận dạng ổ cắm SIO_KEEPALIVE_VALS, // dwIoControlCode (LPVOID) lpvInBuffer, // con trỏ tới tcp_keepalive struct (DWORD) cbInBuffer, // độ dài của bộ đệm đầu vào NULL, // bộ đệm đầu ra 0, // kích thước của bộ đệm đầu ra (LPDWORD) lpcbBytesReturned, // số byte trả về NULL, // cấu trúc OVERLAPPED NULL // quy trình hoàn thành);
Hệ điều hành Linux
Linux có hỗ trợ tích hợp cho keepalive cần để kích hoạt mạng TCP / IP để sử dụng nó. Các chương trình phải yêu cầu kiểm soát lưu giữ cho các ổ cắm của chúng bằng giao diện setsockopt.
int setsockopt (int socket, int level, int optname, const void * optval, socklen_t optlen)
Mỗi ổ cắm máy khách sẽ được tạo bằng java.net.Socket. ID bộ mô tả tệp cho mỗi ổ cắm sẽ truy xuất bằng cách sử dụng phản chiếu java.
Đối với Windows theo tài liệu của Microsoft