Kết nối ổ cắm TCP có "duy trì sự sống" không?


84

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?


1
Chỉ để đảm bảo "http keepalive" thường không liên quan đến socket keepalive, nó nói về tính năng HTTP / 1.1 giữ các kết nối luôn mở cho các yêu cầu khác. Nó chỉ liên quan đến TCP keepalive vì nó cần phát hiện các kết nối TCP bị hỏng (hoặc thường chỉ giữ các socket mở trong thời gian giới hạn).
eckes

Câu trả lời:


72

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.


4
Đó là một ý kiến ​​hay. Bạn không , nhưng nếu bạn không, sau đó bạn có thể không phát hiện một liên kết bị phá vỡ cho đến khi ai đó thực sự muốn làm điều gì đó. Điều nào có thể là một điều tốt (hoặc có thể có hoặc có thể không quan trọng), tùy thuộc vào những gì bạn đang thực sự cố gắng đạt được.
Matthew Scharley

1
@Pacerier: Phụ thuộc vào giao thức, vì nó hoàn toàn phụ thuộc vào giao thức, nhưng đối với các giao thức dựa trên văn bản yêu cầu một lệnh "PING" và "PONG" theo nghĩa đen là khá điển hình.
Matthew Scharley

4
@MatthewScharley: "Ping pong" này đã được triển khai cho chúng tôi, trong các triển khai TCP tiêu chuẩn và được gọi là "keep-living" (xem câu trả lời phổ biến khác cho câu hỏi này). Có một số lý do để triển khai nó ở cấp ứng dụng?
Tim Cooper

7
@TimCooper: Thực sự không phải vậy. Như tôi đã đánh dấu trong phần nhận xét về các câu trả lời khác, việc triển khai TCP không hữu ích cho hầu hết các yêu cầu cấp ứng dụng . Bạn không thể gửi một tệp theo yêu cầu và đối với hầu hết các hệ điều hành, thời gian chờ lưu giữ TCP chỉ có thể định cấu hình ở mức toàn hệ thống và được đặt quá cao để nói chung hữu ích cho các ứng dụng.
Matthew Scharley 28/10/12

13
@Tim Lý do cho việc duy trì hoạt động ở cấp ứng dụng là tiêu chuẩn TCP khuyến nghị đặt bộ hẹn giờ duy trì hoạt động cao hơn hai giờ. Chưa bao giờ thấy một kết nối TCP không có lưu lượng nào tồn tại trong thời gian này. Do đó, công cụ lưu giữ TCP mặc định là vô dụng.
Robert

96

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 đó 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.

Giới thiệu

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 RSTgó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.

Quy trình Keep-Alive

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
    • mặc định 7200 giây
  • tcp_keepalive_probes
    • mặc định 9
  • tcp_keepalive_intvl
    • mặc định 75 giây

Quá trình hoạt động như sau:

  1. Máy khách mở kết nối TCP
  2. Nếu kết nối không hoạt động trong tcp_keepalive_timevài giây, hãy gửi một ACKgói tin trống . 1
  3. Máy chủ có phản hồi với một tương ứng ACKcủa riêng nó không?
    • Không
      1. Chờ tcp_keepalive_intvlvài giây, sau đó gửi mộtACK
      2. Lặp lại cho đến khi số lượng ACKđầu dò đã được gửi bằng nhau tcp_keepalive_probes.
      3. Nếu không nhận được phản hồi tại thời điểm này, hãy gửi một RSTvà ngắt kết nối.
    • : Quay lại bước 2

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).

Gotchas

2 giờ mặc định

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.

Keep-Alive là tùy chọn

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.

Thay đổi thời gian chờ TCP

Mỗi ổ cắm

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.

Linux

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

Mac OS X

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 keepidlekeepintvltheo đơ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 sysctlnà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

các cửa sổ

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 ACKgó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 / JavaLinuxNetflonatel / libdontdie .


Rất hữu ích, cảm ơn! Một bổ sung: Đối với Windows, khởi động lại là bắt buộc để các giá trị mới của KeepAliveTime có hiệu lực.
geld0r

Trên AIX, cài đặt TCP Keep-Alive hiện tại có thể được truy vấn bằng $ no -a | grep tcp_keeplệnh.
Jarek Przygódzki

55

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 setKeepAlivegetKeepAlivephươ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.


4
Nếu tôi là setKeepAlive (true); khoảng thời gian sẽ là bao nhiêu? ... Ngoài ra Java sẽ tiếp tục gửi các thông báo còn tồn tại ở khoảng thời gian mặc định hay tôi sẽ phải làm điều đó theo chương trình?
Kevin Boyd

3
unixguide.net/network/socketfaq/4.7.shtml Có mô tả về SO_KEEPALIVE. Nó không phải là quá nhiều những gì OP muốn, mặc dù nó một tùy chọn dựa trên giao thức những gì tôi đã đề xuất ... tuy nhiên, cứ hai giờ một lần sẽ không làm được nhiều cho các ứng dụng.
Matthew Scharley

4
@MatthewScharley Về "nó không được mặc định là không dưới hai giờ" ... có nghĩa là nó được phép dưới hai giờ phải không?
Pacerier

1
@MatthewScharley - "Bạn nói đúng, nhưng đó sẽ là cách triển khai cụ thể ..." . Khoảng thời gian duy trì sự sống không thể ít hơn hai giờ sẽ vô dụng đến mức khó có ai thực hiện nó.
Stephen C

2
@Daniel - giải pháp thay thế (trong Java) sẽ là làm thủ công duy trì sự sống, như đã đề cập ở trên và trong các câu trả lời khác. Không đẹp, nhưng nó có thể tốt hơn một thay đổi mặc định trên toàn hệ điều hành có thể phá vỡ các dịch vụ hệ thống hoặc các ứng dụng khác.
Stephen C

34

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.


2
Bạn có thể sửa đổi khoảng thời gian lưu giữ TCP cho phù hợp với ứng dụng của mình. Ví dụ: msdn.microsoft.com/en-us/library/dd877220%28VS.85%29.aspx
Dan Berindei

@ZZCoder Bạn có thể giải thích rõ hơn khi bạn nói "Trong HTTP, keepalive có nghĩa là trạng thái kết nối liên tục" có nghĩa là gì không?
Pacerier

1
@Pacerier: Trong HTTP/1.0mỗ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.1họ đã giới thiệu một Keep-Alivetiê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.
Matthew Scharley

Về cơ bản, nó có nghĩa là nhiều yêu cầu HTTP sẽ / nên sử dụng lại cùng một kết nối TCP (Các kết nối này cũng có thể vẫn tồn tại nhưng điều đó không đồng nhất với HTTP nên về cơ bản nó là một khái niệm khác).
Igor Čordaš

24

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.


Ah! bạn thêm một điểm tốt ở đây, có nghĩa là bạn cũng đã xem xét các ở giữa những điều mà có thể cản trở hoạt động của một kết nối như router NAT vv ...
Kevin Boyd

4
Đây là một điểm tốt và là một lời nhắc nhở tốt rằng có nhiều điều cần ghi nhớ hơn là những gì chúng ta đang trực tiếp thực hiện. Ngoài ra, Lemmings !!
Matthew Scharley

Lưu ý rằng việc chia sẻ tệp p2p vừa chiếm nhiều cổng vừa tạo ra nhiều kết nối zombie, khiến nhiều khả năng NAT sẽ cần phải cắt bỏ các kết nối không hoạt động.
Artelius

4
Không nhất thiết, một kết nối TCP được xác định bởi 4 yếu tố: src ip, src port, dest ip, dest port. Vì vậy, bạn có thể sử dụng lại cùng một cổng bên ngoài (nguồn) miễn là ip đích khác nhau.
Dan Berindei

1
Ồ đúng rồi, bạn nói đúng. Tôi nghĩ lý do thực sự là các NAT có một bảng kích thước cố định của các kết nối mở, do hạn chế về bộ nhớ và thời gian tra cứu.
Artelius

4

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).


1

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.


0

Đối với Windows theo tài liệu của Microsoft

  • KeepAliveTime (REG_DWORD, mili giây, theo mặc định không được đặt, có nghĩa là 7.200.000.000 = 2 giờ) - tương tự thành tcp_keepalive_time
  • KeepAliveInterval (REG_DWORD, mili giây, theo mặc định không được đặt, có nghĩa là 1.000 = 1 giây) - tương tự thành tcp_keepalive_intvl
  • Vì Windows Vista không có tương tự với tcp_keepalive_probes, giá trị được cố định thành 10 và không thể thay đổi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.