2010-06-29 36 views
7

Chúng tôi có một kiến ​​trúc máy chủ khách hàng đơn giản giữa thiết bị di động của chúng tôi và máy chủ của chúng tôi đều được viết bằng Java. Một ServerSocket và Socket thực hiện rất đơn giản. Tuy nhiên một trong những vấn đề là khi khách hàng chấm dứt đột ngột (không đóng đúng socket) máy chủ không biết rằng nó bị ngắt kết nối. Hơn nữa, máy chủ có thể tiếp tục ghi vào ổ cắm này mà không nhận được bất kỳ ngoại lệ nào. Tại sao?Ổ cắm Java không ném ngoại lệ trên ổ cắm đã chết?

Theo tài liệu, ổ cắm Java nên ném ngoại lệ nếu bạn cố ghi vào ổ cắm không thể truy cập ở đầu kia!

Trả lời

0

Giao tiếp TCP/IP có thể rất lạ. TCP sẽ thử lại khá lâu ở các tầng dưới cùng của ngăn xếp mà không bao giờ để các lớp trên biết rằng bất cứ điều gì đã xảy ra. Tôi sẽ hoàn toàn mong đợi rằng sau một khoảng thời gian (30 giây đến một vài phút) bạn sẽ thấy một lỗi, nhưng tôi đã không thử nghiệm này tôi chỉ đi ra làm thế nào các ứng dụng TCP có xu hướng làm việc.

Bạn có thể siết chặt các thông số kỹ thuật TCP (thử lại, hết thời gian chờ, vv) nhưng lại không gây rối nhiều.

Ngoài ra, có thể là tôi hoàn toàn sai và việc triển khai Java bạn đang sử dụng chỉ là không ổn định.

2

Kết nối cuối cùng sẽ được hết thời gian chờ bởi Thời gian chờ truyền lại (RTO). Tuy nhiên, RTO được tính sử dụng một thuật toán phức tạp dựa trên độ trễ mạng (RTT), xem RFC này,

http://www.ietf.org/rfc/rfc2988.txt

Vì vậy, trên mạng di động, điều này có thể phút. Đợi 10 phút để xem bạn có thể hết thời gian chờ không.

Giải pháp cho loại vấn đề này là thêm nhịp tim trong giao thức ứng dụng của riêng bạn và ngắt kết nối khi bạn không nhận được ACK cho nhịp tim.

1

Từ khóa ở đây (without closing the socket properly).

Sockets nên luôn luôn được mua lại và xử lý theo cách này:

final Socket socket = ...; // connect code 

try 
{ 
    use(socket); // use socket 
} 
finally 
{ 
    socket.close(); // dispose 
} 

Ngay cả với biện pháp phòng ngừa này, bạn nên xác định timeouts ứng dụng, cụ thể đối với giao thức của bạn.

Trải nghiệm của tôi đã cho thấy, thật không may là bạn không thể sử dụng bất kỳ chức năng hết thời gian chờ nào của Socket (ví dụ: không có thời gian chờ cho thao tác ghi và thậm chí là hoạt động đọc).

Đó là lý do tại sao bạn cần một chuỗi cơ quan giám sát thực thi thời gian chờ ứng dụng của bạn và xử lý các ổ cắm không phản hồi trong một thời gian.

Một cách thuận tiện để thực hiện việc này là khởi tạo Socket và ServerSocket thông qua các kênh tương ứng trong java.nio. Ưu điểm chính của các ổ cắm như vậy là chúng có thể bị gián đoạn, theo cách đó bạn có thể đơn giản làm gián đoạn luồng mà giao thức socket và đảm bảo rằng socket được xử lý đúng cách.

Lưu ý rằng bạn nên thực thi thời gian chờ của ứng dụng ở cả hai bên vì nó chỉ là vấn đề thời gian và may mắn khi bạn có thể gặp phải các ổ cắm không hồi đáp.

0

Để trả lời phần đầu tiên của câu hỏi (về việc không biết rằng máy khách đã ngắt kết nối đột ngột), trong TCP, bạn không thể biết kết nối đã kết thúc cho đến khi bạn cố gắng sử dụng nó.

Khái niệm guaranteed delivery in TCP khá tinh tế: phân phối không thực sự được đảm bảo cho ứng dụng ở đầu bên kia (nó phụ thuộc vào những gì được đảm bảo có nghĩa là thực sự). Section 2.6 of RFC 793 (TCP) cung cấp thêm chi tiết về chủ đề này. This thread on the Restlet-discuss listthis thread on the Linux kernel list cũng có thể được quan tâm.

Đối với phần thứ hai (không phát hiện khi bạn ghi vào ổ cắm này), đây có thể là câu hỏi về bộ đệm và thời gian chờ (như những người khác đã đề xuất).

+0

Tôi đã cố gắng sử dụng nó bằng cách ghi vào ổ cắm và thậm chí sau đó tôi không biết nếu khách hàng đã bị ngắt kết nối. – erotsppa

0

Tôi đang đối mặt với cùng một vấn đề. Tôi nghĩ rằng khi bạn đăng ký ổ cắm với bộ chọn, nó không ném bất kỳ ngoại lệ nào. Bạn có đang sử dụng bộ chọn với ổ cắm của mình không?