2008-08-28 28 views
39

Ok, tôi có một ngoại lệ lạ được ném từ mã của tôi đã khiến tôi bực bội vì tuổi tác.WSACancelBlockingCall exception

System.Net.Sockets.SocketException: A blocking operation was interrupted by a call to WSACancelBlockingCall 
    at System.Net.Sockets.Socket.Accept() 
    at System.Net.Sockets.TcpListener.AcceptTcpClient() 

MSDN không phải là terribly hữu ích về vấn đề này: http://msdn.microsoft.com/en-us/library/ms741547(VS.85).aspx và tôi thậm chí không biết làm thế nào để bắt đầu xử lý sự cố này. Nó chỉ ném 4 hoặc 5 lần một ngày, và không bao giờ trong môi trường thử nghiệm của chúng tôi. Chỉ ở các địa điểm sản xuất và trên tất cả các địa điểm sản xuất.

Tôi đã tìm thấy rất nhiều bài đăng hỏi về ngoại lệ này, nhưng không có câu trả lời dứt khoát thực sự về những gì gây ra nó và cách xử lý hoặc ngăn chặn nó.

Mã này chạy trong một thread nền riêng biệt, phương pháp này bắt đầu:

public virtual void Startup() 
    { 
    TcpListener serverSocket= new TcpListener(new IPEndPoint(bindAddress, port));  
     serverSocket.Start(); 

sau đó tôi chạy một vòng lặp đặt tất cả các kết nối mới như công ăn việc làm trong một hồ bơi thread riêng biệt. Nó trở nên phức tạp hơn vì kiến ​​trúc ứng dụng, nhưng về cơ bản:

while ((socket = serverSocket.AcceptTcpClient()) !=null) //Funny exception here 
    { 
     connectionHandler = new ConnectionHandler(socket, mappingStrategy); 
     pool.AddJob(connectionHandler); 
    } 
    } 

Từ đó, pool có chủ đề riêng của nó mà chăm sóc từng công việc trong chủ đề riêng của nó, riêng biệt.

Hiểu biết của tôi là AcceptTcpClient() là một cuộc gọi chặn, và bằng cách nào đó winsock đang nói cho luồng dừng chặn và tiếp tục thực hiện .. nhưng tại sao? Và tôi phải làm gì đây? Chỉ cần nắm bắt ngoại lệ và bỏ qua nó?


Vâng, tôi nghĩ một số chủ đề khác đang đóng socket, nhưng chắc chắn không phải từ mã của tôi. Những gì tôi muốn biết là: ổ cắm này có được đóng bởi máy khách kết nối (ở phía bên kia của ổ cắm) hay nó bị đóng bởi máy chủ của tôi. Bởi vì vì nó là tại thời điểm này, bất cứ khi nào ngoại lệ này xảy ra, nó tắt cổng nghe của tôi, có hiệu quả đóng dịch vụ của tôi. Nếu điều này được thực hiện từ một vị trí từ xa, thì đó là một vấn đề lớn.

Ngoài ra, điều này có thể đơn giản là máy chủ IIS tắt ứng dụng của tôi, và do đó hủy tất cả các chủ đề nền và phương pháp chặn của tôi?

Trả lời

35

Có thể máy chủSocket đang bị đóng từ một chuỗi khác không? Điều đó sẽ gây ra ngoại lệ này.

+0

Giả sử là vậy. Làm thế nào để bạn đóng nó từ một chủ đề khác? Liệu các ổ cắm cần phải được 'dễ bay hơi'? –

+1

Không, miễn là các chủ đề khác có một tham chiếu đến đối tượng socket, nó có thể đóng nó. – TimK

+0

Làm thế nào bạn có thể đóng socket từ cùng một luồng nếu nó ở trạng thái Block ??? –

4

Điều này có thể xảy ra trên serverSocket.Stop(). Mà tôi gọi bất cứ khi nào Dispose được gọi.

Sau đây là cách xử lý ngoại lệ của tôi cho nghe chủ đề trông giống như:

try 
{ 
    //... 
} 
catch (SocketException socketEx) 
{  
    if (_disposed) 
     ar.SetAsCompleted(null, false); //exception because listener stopped (disposed), ignore exception 
    else 
     ar.SetAsCompleted(socketEx, false); 
} 

Bây giờ những gì đã xảy ra là, tất cả vì vậy thường là những ngoại lệ có thể xảy ra trước khi _disposed được thiết lập là true. Vì vậy, giải pháp cho tôi là làm cho mọi thứ đều an toàn.

3

Tương tự tại đây! Nhưng tôi đã tìm ra, rằng ReceiveBuffer trên 'phía máy chủ' đã bị tràn ngập từ phía khách hàng! (Trong trường hợp của tôi là một loạt các máy quét RFID, người đã tiếp tục gửi spam mã thẻ, thay vì dừng gửi cho đến khi mã thẻ tiếp theo đến)

Nó giúp nâng cao trình nhận dạng và định cấu hình lại máy quét ...

5

Đây là giải pháp ví dụ của tôi để tránh WSAcancelblablabla: Xác định chủ đề của bạn như toàn cầu thì bạn có thể sử dụng phương pháp invoke như thế này:

private void closinginvoker(string dummy) 
    { 
     if (InvokeRequired) 
     { 
      this.Invoke(new Action<string>(closinginvoker), new object[] { dummy }); 
      return; 
     } 
     t_listen.Abort(); 
     client_flag = true; 
     c_idle.Close(); 
     listener1.Stop(); 
    } 

Sau khi bạn gọi nó, đóng thread đầu tiên thì mãi mãi lặp cờ để nó chặn thêm chờ đợi (nếu bạn có nó), sau đó đóng tcpclient sau đó dừng người nghe.