2009-05-22 37 views
12

Tôi hiện đang duy trì một số phần mềm máy chủ web và tôi cần thực hiện rất nhiều hoạt động I/O. Các cuộc gọi read(), write(), close()shutdown(), khi được sử dụng trên ổ cắm, đôi khi có thể gây ra lỗi ENOTCONN. Lỗi này có nghĩa là gì? Các điều kiện nào sẽ kích hoạt nó? Tôi có thể không bao giờ có vẻ để tái sản xuất nó tại địa phương nhưng có những người dùng có thể.Nguyên nhân gây ra lỗi ENOTCONN?

Ngay bây giờ tôi chỉ bỏ qua ENOTCONN khi được nâng lên bởi close()shutdown() vì nó có vẻ vô hại, nhưng tôi không hoàn toàn chắc chắn.

EDIT:

  • Tôi hoàn toàn chắc chắn rằng cuộc gọi connect() thành công. Tôi kiểm tra giá trị trả lại của nó.
  • ENOTCONN thường được nâng lên bởi close()shutdown(). Tôi chỉ hiếm khi nhìn thấy một số read()write() nâng cao ENOTCONN.
+0

Hệ điều hành nào? Tôi đang theo dõi một vấn đề tương tự tại nơi làm việc trên một hệ thống Solaris 10 cũ. Cảm ơn. – Nemo

+0

Chủ yếu là FreeBSD.Trong thời gian đó tôi đã phát hiện ra rằng có các lỗi hạt nhân trong FreeBSD có thể gây ra close() và shutdown() để trả về ENOTCONN sai khi xử lý các socket miền Unix. Solaris cũng có các lỗi hạt nhân khác nhau w.r.t. Các ổ cắm miền Unix, mặc dù tôi chỉ quan sát thấy các lỗi trong kết nối(). – Hongli

Trả lời

13

Nếu bạn chắc chắn rằng không có gì ở bên cạnh kết nối TCP của bạn đang đóng kết nối, thì âm thanh với tôi như phía xa đang đóng kết nối.

ENOTCONN, như những người khác đã chỉ ra, chỉ đơn giản có nghĩa là ổ cắm không được kết nối. Điều này không nhất thiết có nghĩa là connect không thành công. Ổ cắm cũng có thể đã được kết nối trước đó, nó chỉ là không tại thời điểm cuộc gọi dẫn đến ENOTCONN.

Điều này khác với:

  • ECONNRESET: đầu kia của kết nối gửi một gói tin TCP reset. Điều này có thể xảy ra nếu đầu kia từ chối kết nối hoặc không thừa nhận rằng kết nối đó đã được kết nối, trong số những thứ khác.
  • ETIMEDOUT: điều này thường chỉ áp dụng cho connect. Điều này có thể xảy ra nếu nỗ lực kết nối không thành công trong một khoảng thời gian phụ thuộc vào hệ thống.

EPIPE đôi khi có thể được trả về bởi một số cuộc gọi hệ thống liên quan đến ổ cắm trong điều kiện ít nhiều giống như ENOTCONN.Ví dụ: trên một số hệ thống, EPIPEENOTCONN là đồng nghĩa khi được trả về bởi send.

Trong khi nó không phải là bất thường đối với shutdown trở ENOTCONN, vì chức năng này là nghĩa vụ phải phá bỏ kết nối TCP, tôi sẽ ngạc nhiên khi thấy close trở ENOTCONN. Nó thực sự không bao giờ nên làm điều đó.

Cuối cùng, như đã đề cập, EBADF không nên áp dụng trong trường hợp của bạn trừ khi bạn đang thử một số thao tác trên bộ mô tả tệp đã là close d. Có một ổ cắm bị ngắt kết nối (tức là kết nối TCP đã bị hỏng) không giống như việc đóng bộ mô tả tệp được kết hợp với socket đó.

+0

Bạn sai: phía bên kia đóng kết nối không phải là lý do tắt máy() hoặc đóng() thành không thành công. ENOTCONN cũng không bật tắt() cho biết không có RESET thực sự xảy ra trong thực tế. (Xem câu trả lời của tôi để biết thêm chi tiết.) –

+0

@ Robert: Tôi không nghĩ tôi đã nói điều đó. Tôi chỉ thấy rằng tôi đã nói rằng 'ENOTCONN' có thể được trả về bằng' shutdown' (điều này hoàn toàn đúng) và nó không bao giờ được trả về bởi 'close', như OP đã nói rằng anh ta đã quan sát (cũng hoàn toàn đúng) . –

+0

Bạn nói cả hai, rằng ENOTCONN đã được trả về vì phía từ xa đã đóng kết nối _and_ mà nó khác với ECONNRESET. - Tôi nói rằng ENOTCONN không bao giờ được trả lại cho một kết nối từ xa thông thường. Tôi cũng tin rằng việc shutdown() có thể trả về ENOTCONN trong các trường hợp ECONNRESET, vì sau này không được trả về bởi shutdown(). –

0

endpoint Giao thông vận tải không được kết nối

Các ổ cắm được gắn liền với một giao thức hướng kết nối và chưa được kết nối. Đây thường là một lỗ hổng lập trình.

Từ: http://www.wlug.org.nz/ENOTCONN

+1

Tôi biết tên lỗi, nhưng nó có nghĩa là gì *? Điểm cuối giao thông này mà nó đề cập đến và điều này khác với EPIPE, ECONNRESET và ETIMEDOUT như thế nào? – Hongli

+0

Tôi đoán bạn không gọi kết nối() hoặc không kiểm tra xem kết nối() đã thành công chưa. –

+0

Tôi đã làm, nó đã thành công. Người dùng đã báo cáo vấn đề này quan sát thấy rằng công việc read() s và write() chỉ hoạt động tốt, nhưng vào lúc shutdown() và close() nó làm tăng ENOTCONN. Tôi không thể sao chép nó một cách cục bộ, và cũng không làm hầu hết người dùng gặp vấn đề này. – Hongli

0

Nếu bạn chắc chắn bạn đã kết nối đúng ở nơi đầu tiên, ENOTCONN rất có thể là do một trong hai fd bị đóng cửa vào ngày cuối cùng của bạn trong khi (có lẽ trong thread khác?) bạn đang ở giữa yêu cầu hoặc kết nối bị ngắt khi bạn đang ở giữa yêu cầu.

Trong mọi trường hợp, điều đó có nghĩa là ổ cắm không được kết nối. Đi trước và dọn sạch ổ cắm đó. Nó đã chết rồi. Không có vấn đề gì khi gọi close() hoặc shutdown() trên đó.

+0

Tôi chắc chắn rằng fd không bị đóng bởi một chuỗi khác. Nhưng giả sử như vậy, liệu điều đó có gây ra EBADFD không? Hơn nữa, nó thường đóng() và tắt() làm tăng ENOTCONN, không đọc() và viết(). Điều này có nghĩa là gì? – Hongli

+0

Lưu ý trong câu trả lời của tôi, tôi chỉ định "ở giữa yêu cầu". Vì vậy, bạn thực hiện cuộc gọi và thực hiện chuyển sang một quy trình khác. Sau đó, kết nối giảm xuống, và quá trình của bạn bắt đầu thực hiện ... EBADFD không và không đúng (đó là một fd hợp lệ), nhưng bạn không kết nối. Vì vậy, bạn nhận được ENOTCONN. – dwc

1

Tôi tin rằng ENOTCONN được trả về, vì tắt máy() không được phép trả lại lỗi ECONNRESET hoặc các lỗi chính xác khác.

Giả sử phía bên kia “chỉ” đóng kết nối. Ở cấp TCP, phía bên kia chỉ có thể đóng một nửa kết nối (hoặc hủy bỏ kết nối). Kết nối là hoàn toàn bình thường nếu cả hai bên đều tắt máy() (hoặc đóng()). Nếu cả hai bên làm điều đó, tắt máy() thực sự thành công cho cả hai bên!

Vấn đề là tắt máy() đã làm không thành công trong kết nối bình thường (nửa), không kết nối đầu tiên, cũng như kết nối thứ hai. - Từ các lỗi được liệt kê trong tài liệu POSIX cho shutdown(), ENOTCONN là ít nhất là không thích hợp, bởi vì các lỗi khác cho thấy các vấn đề với các đối số được truyền tới shutdown() (hoặc các vấn đề tài nguyên cục bộ để xử lý yêu cầu).

Vậy điều gì đã xảy ra? Những ngày này, một thiết bị NAT ở đâu đó giữa hai bên liên quan có thể đã giảm liên kết và gửi các gói RESET như một phản ứng. Thiết lập lại các kết nối rất phổ biến cho IPv4, bạn sẽ nhận được chúng ở bất cứ nơi nào trong mã của bạn, thậm chí được che dấu là ENOTCONN trong shutdown().

Lỗi mã hóa cũng có thể là lý do. Trên một ổ cắm không chặn, ví dụ, một kết nối() có thể trả về 0 mà không chỉ ra một kết nối thành công.

+0

Nó đã được xác nhận là lỗi hạt nhân FreeBSD. Mã lỗi ENOTCONN đã được quan sát trên các ổ cắm miền Unix vì vậy TCP không thể có bất cứ điều gì để làm với nó anyway. – Hongli

+0

Tôi đã xem qua câu hỏi của bạn trong khi tìm kiếm lý do tại sao ENOTCONN được trả về trong khi hoạt động trên một TCP-socket đã kết nối trước đó. (Và không phải là trường hợp của bạn, nhưng câu hỏi vẫn còn trong không khí.) - Và tôi cảm thấy bắt buộc phải trả lời vì lý do là: một (hạt nhân) lỗi ở đâu đó hoặc một điều kiện lỗi của kết nối, được dán nhãn không phù hợp ENOTCONN. Lý do là và không phải là một kết nối từ xa bình thường. Câu trả lời đó là không chính xác cho cả hai ổ cắm miền unix (trường hợp của bạn) và ổ cắm TCP (trường hợp của tôi). –

1

Đó là bởi vì, tại thời điểm ngắt() ổ cắm, bạn có dữ liệu trong bộ đệm của ổ cắm đang đợi để được gửi đến bên từ xa đã đóng() hoặc ngắt() ổ cắm nhận của nó. Tôi không hiểu cách ổ cắm hoạt động như thế nào, tôi khá thất vọng, và tôi thậm chí không tìm thấy các tập tin mà chức năng "tắt máy" này được thực hiện, nhưng thấy rằng thực tế không có hướng dẫn sử dụng cho toàn bộ ổ cắm. bắt đầu thử tất cả các khả năng cho đến khi tôi gặp lỗi trong môi trường "được kiểm soát". Nó có thể là một cái gì đó khác, nhưng sau nhiều cố gắng đây là những lời giải thích tôi giải quyết cho:

  • Nếu bạn gửi dữ liệu sau khi từ xa đóng kết nối, khi bạn tắt máy(), bạn sẽ gặp lỗi.
  • Nếu bạn gửi dữ liệu trước khi từ xa đóng kết nối nhưng không nhận được kết nối() ở đầu kia, bạn có thể tắt() một lần, lần sau khi bạn tắt máy(), bạn gặp lỗi.
  • Nếu bạn không gửi bất kỳ dữ liệu nào, bạn có thể tắt tất cả thời gian bạn muốn, miễn là bên từ xa không tắt(); một khi phía xa đã tắt máy(), nếu bạn cố gắng tắt máy() và ổ cắm đã được tắt(), bạn sẽ gặp lỗi.
Các vấn đề liên quan