2013-08-22 43 views
9

Bối cảnh:
Tôi có một số mã đang kết nối với máy chủ để lấy dữ liệu. Tuy nhiên, tại một số điểm chương trình đã đi vào một trạng thái mà nó đã không kết nối với máy chủ. Vấn đề chúng tôi đã thấy là máy chủ đã liên tục định thời gian khi chúng tôi cố gắng kết nối lại.Đóng tất cả các kết nối mạng cơ bản

Plugin:
Chúng tôi đã đặt thời gian chờ thành giá trị mặc định được plugin mạng của chúng tôi sử dụng (plugin Thrift). Các giá trị này là thời gian chờ 100k mili giây và thời gian chờ ghi đè 300k milli giây. Không chính xác thời gian chờ ngắn. Ngoài ra, mỗi lần chúng tôi cố gắng kết nối lại, chúng tôi tạo lại lớp của plugin, vì vậy bất kỳ giá trị nào mà cài đặt trong nội bộ được đặt lại mỗi lần chúng tôi cố gắng kết nối lại. Tôi tin rằng thời gian chờ không phải là vấn đề. Và tôi tin rằng plugin không phải là vấn đề.

Mạng:
Chúng tôi đã thấy những thời gian chờ lặp lại này xảy ra trong nửa giờ. Khi chúng tôi khởi động lại dịch vụ (không phải máy), nó ngay lập tức trở lại trực tuyến. Vì vậy, tôi biết nó không phải là một vấn đề mạng. Điều đó khiến tôi tin rằng đó là điều gì đó trong mã của chúng tôi đang xâm nhập vào trạng thái mạng không hợp lệ. Ngoài ra, nó là một trạng thái mà chúng tôi không thể kiểm soát, vì plugin của chúng tôi ẩn tất cả các công cụ mạng tốt từ chúng tôi - bao gồm hết thời gian chờ, cờ cố định và nhóm kết nối (trong số những người khác). Về cơ bản, chúng tôi không có quyền truy cập vào thành viên HTTPWebReqest.

Câu hỏi:
Khi cài đặt mạng của chúng tôi vào trạng thái này, chúng tôi cố gắng đóng tất cả các kết nối và kết nối lại với máy chủ. Mục đích là để tiêu diệt tất cả các kết nối đang hoạt động để thiết lập lại bất kỳ trạng thái nào mà chúng ta có được. Tuy nhiên, khi chúng tôi cố gắng kết nối lại, chúng tôi sẽ bị hết thời gian chờ kết nối lại. Bằng cách nào đó (có thể do KeepAlive và TCP Pipelining, mà chúng tôi không thể kiểm soát), các kết nối mạng vẫn mở ngay cả khi chúng tôi đã đóng tất cả các kết nối. Điều này khiến chúng tôi ở trạng thái xấu và ngăn chúng tôi chuyển các kết nối của chúng tôi đến máy chủ.

Câu hỏi:
Làm thế nào tôi có thể tiêu diệt tất cả các kết nối cơ bản đến máy chủ để buộc kết nối lại?

+7

Cá nhân, tôi khuyên bạn nên thay đổi thư viện bạn đang sử dụng. Tuy nhiên, vì tôi là bạn, tôi biết rằng đó không phải là một lựa chọn. – Richard

+0

+1. Đẹp tự nhận xét và trả lời – Danexxtone

Trả lời

9

Kiến trúc cơ bản .Net sẽ duy trì kết nối (qua KeepAlive) để cải thiện hiệu suất mạng tổng thể. Giải pháp đơn giản nhất là chỉ cần đặt KeepAlive thành false trên tất cả các kết nối của bạn để chúng không duy trì trạng thái không hợp lệ đó. Nhược điểm là bạn sẽ tăng lưu lượng truy cập của bạn vì họ sẽ phải thiết lập lại các kết nối mỗi lần.

Ngoài ra, vì bạn không có quyền truy cập vào mục tiêu (hoặc đối tượng HTTPWebRequest), bạn sẽ phải tìm cách giết các kết nối bên ngoài cài đặt yêu cầu.

Có hai phương pháp bạn có thể thực hiện để nhận .Net để giải phóng các kết nối này. Cả hai đều liên quan đến việc xuống cấp ServicePoint và xử lý các nhóm kết nối.

  1. CloseConnectionGroups

    Khi bạn tạo bạn HttpWebRequest, bạn có thể cung cấp cho nó một nhóm kết nối. Từ đó, bạn có thể sử dụng chức năng CloseConnectionGroup() từ ServicePoint để tiêu diệt tất cả các kết nối đến dịch vụ đó.

    ServicePoint srvrPoint = ServicePointManager.FindServicePoint(serverUri); 
    srvrPoint.CloseConnectionGroup(myConnGroup) 
    

    Tất nhiên, nếu bạn có nhiều nhóm kết nối, bạn sẽ cần thực hiện điều đó trong vòng lặp cho mọi nhóm kết nối.

    Lưu ý rằng nếu bạn chọn đường dẫn này, hãy cẩn thận không đặt tất cả các kết nối trong cùng một nhóm. Điều này có thể khiến bạn hết ổ cắm. More information here.

  2. ReleaseAllConnectionGroups

    Có một chức năng nội bộ trong lớp ServicePoint mà bạn có thể gọi đó là sẽ giết chết tất cả các kết nối đến các điểm dịch vụ cung cấp cho (ví dụ máy chủ). Tuy nhiên, vì nội bộ của lớp học, bạn sẽ phải sử dụng sự phản chiếu để có được nó:

    ServicePoint srvrPoint = ServicePointManager.FindServicePoint(serverUri); 
        MethodInfo ReleaseConns = srvrPoint.GetType().GetMethod 
          ("ReleaseAllConnectionGroups", 
          BindingFlags.Instance | BindingFlags.NonPublic); 
        ReleaseConns.Invoke(srvrPoint, null); 
    

    Mã này chỉ cần rút ra ReleaseAllConnectionGroups từ ServerPoint đó và gọi nó không có tham số. Chức năng này sẽ đi qua tất cả các nhóm kết nối trong danh sách nội bộ của nó và giải phóng tất cả các tài nguyên đó - tiêu diệt tất cả các kết nối.

    Sự sụp đổ: Vì đây là một thành viên riêng tư, bạn không được đảm bảo rằng nó sẽ ở đó nếu bạn nâng cấp phiên bản .Net của mình. Nó hiện đang có sẵn trong phiên bản 2.0 đến 4.5, mặc dù. Liên kết đến the reverse engineered code of ReleaseAllConnectionGroups.

Bởi vì bạn không thể thiết lập các nhóm kết nối, bạn sẽ phải sử dụng tùy chọn 2.

Thật không may, không có cách nào khác để có được Net để đóng những kết nối ở mức độ thấp và giải phóng KeepAlive của họ trạng thái mà không đặt cờ KeepAlive.

+1

Sau khi dành nhiều thời gian để khắc phục sự cố, tôi đã xem xét giải pháp này. Nó làm việc như quyến rũ đối với tôi. Cảm ơn –

0

Tại sao không sử dụng mã folowing:

SqlConnection.ClearAllPools();

Tôi sử dụng trong tất cả các ứng dụng của mình.