2010-09-21 27 views
6

Tất cả, tôi đang cố gắng hủy hai HttpWebRequests đồng thời bằng một phương thức tương tự như mã bên dưới (được hiển thị trong giả C#).Giết HttpWebRequest đối tượng bằng cách sử dụng Thread.Abort

Phương pháp chính tạo hai luồng tạo HttpWebRequests. Nếu người dùng muốn, họ có thể hủy bỏ các yêu cầu bằng cách nhấp vào một nút mà sau đó gọi phương pháp Abort.

private Thread first; 
private Thread second; 
private string uri = "http://somewhere"; 

public void Main() 
{ 
    first = new Thread(GetFirst); 
    first.Start(); 

    second = new Thread(GetSecond); 
    second.Start(); 

    // Some block on threads... like the Countdown class 
    countdown.Wait(); 
} 

public void Abort() 
{ 
    try 
    { 
    first.Abort(); 
    } 
    catch { // do nothing } 

    try 
    { 
    second.Abort(); 
    } 
    catch { // do nothing } 
} 

private void GetFirst(object state) 
{ 
    MyHandler h = new MyHandler(uri); 
    h.RunRequest(); 
} 

private void GetSecond(object state) 
{ 
    MyHandler h = new MyHandler(uri); 
    h.RunRequest(); 
} 

Các chủ đề đầu tiên bị gián đoạn bởi một SocketException:

A blocking operation was interrupted by a call to WSACancelBlockingCall 

Các chủ đề thứ hai treo trên GetResponse().

Làm cách nào để hủy bỏ cả hai yêu cầu này theo cách mà máy chủ web biết rằng kết nối đã bị hủy? và/hoặc, Có cách nào tốt hơn để thực hiện việc này không?

CẬP NHẬT

Như đã đề cập, một lựa chọn tốt sẽ được sử dụng BeginGetResponse. Tuy nhiên, tôi không có quyền truy cập vào đối tượng HttpWebRequest - nó được tóm tắt trong lớp MyHandler. Tôi đã sửa đổi câu hỏi để hiển thị điều này.

public class MyHandler 
{ 
    public void RunRequest(string uri) 
    { 
    HttpWebRequest req = HttpWebRequest.Create(uri); 
    HttpWebResponse res = req.GetResponse(); 
    } 
} 
+0

Thật không may, tất cả những gì tôi có thể cung cấp như là một câu trả lời cho điều đó là sửa đổi MyHandler nếu bạn có quyền truy cập vào nó. Nếu không, cách duy nhất để giết nó là cách bạn hiện đang thực hiện nó. Ngoài ra, bạn có thể cung cấp thời gian chờ bằng cách sử dụng tùy chọn HttpWebRequest.Timeout: http: //msdn.microsoft.com/en-us/library/system.net.httpwebrequest.timeout.aspx –

Trả lời

4

để bắt đầu cuộc gọi và sau đó sử dụng phương thức Abort trên lớp để hủy.

http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest_methods.aspx

Tôi tin Abort sẽ không làm việc với các đồng bộ GetResponse:

http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.abort.aspx

Nếu bạn phải gắn bó với phiên bản đồng bộ, để giết tình hình, tất cả các bạn có thể làm là hủy bỏ chủ đề. Từ bỏ chờ đợi, bạn có thể chỉ định một thời gian chờ:

http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.timeout.aspx

Nếu bạn cần phải giết chết quá trình, tôi sẽ tranh luận khởi chạy nó bên trong một AppDomain mới và thả các AppDomain khi bạn muốn giết được yêu cầu; thay vì hủy bỏ một sợi bên trong quá trình chính của bạn.

+1

Adam - Bạn có thể xây dựng trên nhận xét của mình không " tin rằng Abort sẽ không hoạt động với GetResponse đồng bộ "? Bạn tìm thấy ở đâu? – Armbrat

+0

Nó không được đề cập một cách rõ ràng, nhưng câu: "Phương pháp Abort sẽ thực hiện đồng bộ cuộc gọi được chỉ định cho các phương thức BeginGetRequestStream hoặc BeginGetResponse nếu phương thức Abort được gọi trong khi một trong các thao tác này là xuất sắc." khiến tôi ngụ ý rằng nó chỉ hợp lệ với những phương pháp đó. Ngoài ra, trừ khi bạn thực hiện cuộc gọi cross-thread vào đối tượng HttpWebRequest của mình, bạn sẽ không thể gọi Abort vì nó hiện bị chặn trên GetResponse. –

3

Một ThreadAbortException là rất không cụ thể. HttpWebRequest đã hỗ trợ một cách để hủy yêu cầu theo cách có thể dự đoán được bằng phương thức Abort(). Tôi khuyên bạn nên sử dụng nó thay thế.

Lưu ý rằng bạn vẫn sẽ nhận được một ngoại lệ về chủ đề trên web, được thiết kế để cho bạn biết rằng yêu cầu đã bị hủy bỏ bên ngoài. Hãy chuẩn bị để bắt nó.

2

Điều này có thể do tính năng kết nối của .NET. Mỗi cá thể WebRequest có một ServicePoint mô tả mục tiêu bạn muốn liên lạc với (địa chỉ máy chủ, cổng, giao thức, ...). Các ServicePoints này sẽ được tái sử dụng, vì vậy nếu bạn tạo 2 WebRequests với cùng một địa chỉ máy chủ, cổng và giao thức mà chúng sẽ chia sẻ cùng một cá thể ServicePoint.

Khi bạn gọi WebRequest.GetResponse(), nó sử dụng nhóm kết nối do ServicePoint cung cấp để tạo kết nối.Nếu sau đó bạn hủy luồng bằng Thread.Abort(), nó sẽ KHÔNG trả lại kết nối đến nhóm kết nối của ServicePoint, do đó ServicePoint cho rằng kết nối này vẫn đang được sử dụng. Nếu đạt đến giới hạn kết nối của ServicePoint (mặc định: 2) nó sẽ không tạo ra bất kỳ kết nối mới nào, mà thay vào đó hãy đợi một trong các kết nối mở được trả về.

Bạn có thể tăng giới hạn kết nối như thế này:

HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url); 
httpRequest.ServicePoint.ConnectionLimit = 10; 

hoặc bạn có thể sử dụng giới hạn kết nối mặc định, vì vậy mỗi ServicePoint mới sẽ sử dụng giới hạn này:

System.Net.ServicePointManager.DefaultConnectionLimit = 10; 

Bạn cũng có thể sử dụng ServicePoint .CurrentConnections để nhận số lượng kết nối mở.

Bạn có thể sử dụng các phương pháp sau đây để hủy bỏ thread của bạn:

private Thread thread; 
    private Uri uri; 

    void StartThread() 
    { 
     thread = new Thread(new ThreadStart(() => 
     { 
      WebRequest request = WebRequest.Create(uri); 
      request.ConnectionGroupName = "SomeConnectionGroup"; 

      var response = request.GetResponse(); 

      //... 
     })); 
     thread.Start(); 
    } 

    void AbortThread() 
    { 
     thread.Abort(); 
     ServicePointManager.FindServicePoint(uri).CloseConnectionGroup("SomeConnectionGroup"); 
    } 

Hãy nhớ rằng tất cả các kết nối với cùng máy chủ (hoặc ServicePoint) có tên nhóm kết nối tương tự sẽ bị giết. Nếu bạn có nhiều chuỗi đồng thời, bạn có thể chỉ định tên nhóm kết nối duy nhất cho chúng.

Các vấn đề liên quan