2012-01-27 52 views
11

Tôi có một Dịch vụ .NET Windows để sinh ra một chuỗi về cơ bản chỉ hoạt động như một HttpListener. Đây là hoạt động tốt trong chế độ đồng bộ ví dụ ...Xử lý nhiều yêu cầu với C# HttpListener

private void CreateLListener() 
{ 
    HttpListenerContext context = null; 
    HttpListener listener = new HttpListener(); 
    bool listen = true; 

    while(listen) 
    { 
     try 
     { 
      context = listener.GetContext(); 
     } 
     catch (...) 
     { 
      listen = false; 
     } 
     // process request and make response 
    } 
} 

Vấn đề bây giờ tôi có là tôi cần điều này để làm việc với nhiều yêu cầu và họ đã trả lời đồng thời hoặc ít nhất là trong một cách chồng chéo.

Để giải thích thêm - ứng dụng khách là ứng dụng trình phát đa phương tiện bắt đầu bằng cách thực hiện yêu cầu cho tệp phương tiện với thuộc tính tiêu đề yêu cầu Range bytes=0-. Theo như tôi có thể nói nó làm điều này để làm việc ra những gì các phương tiện truyền thông container.

Sau khi đã đọc một đoạn '' (hoặc nếu nó đã đọc đủ để xác định loại phương tiện), sau đó thực hiện một yêu cầu khác (từ một số ổ cắm máy khách khác) với Range bytes=X-Y. Trong trường hợp này Y là Content-Length được trả về trong phản hồi đầu tiên và X là 250000 byte nhỏ hơn (được phát hiện bằng IIS như là một thử nghiệm). Ở giai đoạn này, nó nhận được 'đoạn cuối' cuối cùng để xem liệu nó có thể nhận được dấu thời gian truyền thông để đo chiều dài hay không.

Sau khi đọc xong, nó thực hiện một yêu cầu khác với Range bytes=0- (từ một số ổ cắm khác) để bắt đầu truyền trực tuyến tệp phương tiện.

Bất cứ lúc nào, nếu người dùng của khách hàng thực hiện thao tác 'bỏ qua', nó sẽ gửi một yêu cầu khác (từ một số ổ cắm khác) với Range bytes=Z- trong đó Z là vị trí nhảy vào tệp phương tiện.

Tôi không phải là rất tốt với các công cụ HTTP nhưng theo như tôi có thể nói tôi cần phải sử dụng nhiều chủ đề để xử lý mỗi yêu cầu/phản ứng trong khi cho phép HttpListener gốc để trở về nghe. Tôi đã thực hiện rất nhiều tìm kiếm nhưng không thể tìm thấy một mô hình có vẻ phù hợp.

EDIT:

Lời cảm ơn và tri ân tới Rick Strahl cho các ví dụ sau đây mà tôi đã có thể thích ứng cho phù hợp với nhu cầu của tôi ...

Add a Web Server to your .NET 2.0 app with a few lines of code

Trả lời

12

Nếu bạn cần một lựa chọn đơn giản hơn cho BeginGetContext, bạn chỉ có thể xếp hàng công việc trong ThreadPool, thay vì thực hiện chúng trên chuỗi chính.Giống như ví dụ:

private void CreateLListener() { 
    //.... 
    while(true) { 
     ThreadPool.QueueUserWorkItem(Process, listener.GetContext());  
    } 
} 
void Process(object o) { 
    var context = o as HttpListenerContext; 
    // process request and make response 
} 
+2

Cách tốt nhất để làm điều đó, nhưng nắm bắt được với chương trình Async sẽ giúp bạn tốt hơn –

10

Bạn cần phải sử dụng async để có thể xử lý nhiều yêu cầu. Vì vậy, bạn sẽ sử dụng phương thức e BeginGetContextEndGetContext.

Có giao diện here.

Mô hình đồng bộ là thích hợp nếu ứng dụng của bạn nên chặn trong khi chờ đợi một yêu cầu khách hàng và nếu bạn muốn xử lý chỉ một * yêu cầu tại một thời điểm *. Sử dụng mô hình đồng bộ, gọi phương thức GetContext , đợi cho khách hàng gửi yêu cầu. Phương thức trả về một đối tượng HttpListenerContext cho bạn để xử lý khi xảy ra.

+0

Async công trình khác nhau để đồng bộ hóa (rõ ràng). Các cuộc gọi để bắt đầu ngay lập tức sẽ trở lại, vì vậy bạn cần phải đối phó với điều đó, do đó hầu hết các ứng dụng có một số loại waitone. Điều đó sẽ không chặn mặc dù. Cuộc gọi lại mà bạn đã chỉ định khi bạn gọi bắt đầu sẽ thực hiện trên một chuỗi mới. Trong đó bạn gọi kết thúc bằng cách bắt đầu lại để tiếp tục nghe và sau đó bạn làm công việc của bạn. yêu cầu mới được xử lý trên các chủ đề mới cho đến khi bạn quyết định dừng nghe. –

+2

@MisterSquonk vui mừng vì nó làm việc cho bạn. Chúng tôi không cho cá ở đây, nhưng dạy câu cá. :) – Aliostad

5

Nếu bạn đang ở đây từ tương lai và cố gắng để xử lý nhiều yêu cầu đồng thời với một chủ đề duy nhất sử dụng async/chờ đợi ..

public async Task Listen(string prefix, int maxConcurrentRequests, CancellationToken token) 
{ 
    HttpListener listener = new HttpListener(); 
    listener.Prefixes.Add(prefix); 
    listener.Start(); 

    var requests = new HashSet<Task>(); 
    for(int i=0; i < maxConcurrentRequests; i++) 
     requests.Add(listener.GetContextAsync()); 

    while (!token.IsCancellationRequested) 
    { 
     Task t = await Task.WhenAny(requests); 
     requests.Remove(t); 

     if (t is Task<HttpListenerContext>) 
     { 
      var context = (t as Task<HttpListenerContext>).Result; 
      requests.Add(ProcessRequestAsync(context)); 
      requests.Add(listener.GetContextAsync()); 
     } 
    } 
} 

public async Task ProcessRequestAsync(HttpListenerContext context) 
{ 
    ...do stuff... 
} 
+1

Nếu bạn quan tâm đến Ngoại lệ từ ProcessRequestAsync, và bạn nên quan tâm, đừng quên gọi t.Wait() trong một nhánh khác. Tất cả trong tất cả tôi thích cách tiếp cận này +1. – frast

+0

Một vấn đề khác là điều kiện trong khi chỉ được kiểm tra nếu một trong các nhiệm vụ WhenAny hoàn thành. – frast

+0

bạn có thể giải thích lý do tại sao chỉ kiểm tra trên WhenAny là một vấn đề @frast? – LightLabyrinth

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