Tình huống mà tôi có trong Windows XP (SP3) đã khiến tôi phát điên, và tôi sắp hết hạn, vì vậy có thể ai đó có thể cung cấp một số nguồn cảm hứng.Tại sao cửa sổ chọn() không phải lúc nào cũng thông báo cho lựa chọn của luồng B() khi luồng A đóng đầu cuối của một cặp socket?
Tôi có chương trình nối mạng C++ (không phải GUI). Chương trình này được xây dựng để biên dịch và chạy dưới Windows, MacOS/X và Linux, do đó, nó sử dụng select() và non-blocking I/O làm cơ sở cho vòng lặp sự kiện của nó.
Ngoài nhiệm vụ mạng của mình, chương trình này cần phải đọc lệnh văn bản từ stdin và thoát ra một cách duyên dáng khi stdin bị đóng. Dưới Linux và MacOS/X, thật dễ dàng - tôi chỉ bao gồm STDIN_FILENO trong fd_set đã đọc của tôi để select(), và select() trả về khi stdin được đóng lại. Tôi kiểm tra xem FD_ISSET (STDIN_FILENO, & readSet) là đúng, cố gắng đọc một số dữ liệu từ stdin, recv() trả về 0/EOF, và vì vậy tôi thoát khỏi quá trình.
Trong Windows, mặt khác, bạn không thể chọn trên STDIN_FILE_HANDLE, vì nó không phải là ổ cắm thực. Bạn cũng không thể thực hiện các lần đọc không chặn trên STDIN_FILE_HANDLE. Điều đó có nghĩa là không có cách nào để đọc stdin từ chuỗi chính, vì ReadFile() có thể chặn vô thời hạn, khiến cho luồng chính ngừng phân phối chức năng mạng của nó.
Không sao, tôi nói, tôi sẽ chỉ sinh ra một sợi chỉ để xử lý stdin cho tôi. Chủ đề này sẽ chạy trong một vòng lặp vô hạn, chặn trong ReadFile (stdinHandle), và bất cứ khi nào ReadFile() trả về dữ liệu, stdin-thread sẽ ghi dữ liệu đó vào một socket TCP. Đầu kia của kết nối của socket đó sẽ được chọn() 'd trên luồng chính, vì vậy luồng chính sẽ thấy dữ liệu stdin đến qua kết nối, và xử lý "stdin" theo cùng cách nó sẽ theo bất kỳ hệ điều hành nào khác. Và nếu ReadFile() trả về false để chỉ ra rằng stdin đã đóng, stdin-thread chỉ đóng đầu cuối của cặp socket sao cho luồng chính sẽ được thông báo qua select(), như được mô tả ở trên. Tất nhiên, Windows không có chức năng socketpair() tốt, vì vậy tôi phải tự cuộn bằng cách sử dụng listen(), connect() và accept() (như đã thấy trong hàm CreateConnectedSocketPair() here. Nhưng tôi đã làm điều đó, và dường như nó hoạt động, nói chung:
Vấn đề là nó không hoạt động 100%. Cụ thể, nếu stdin được đóng trong vòng vài trăm mili giây khi chương trình khởi động, về một nửa thời gian chủ đề chính không nhận được bất kỳ thông báo rằng stdin-end của cặp socket đã được đóng lại, ý tôi là, tôi có thể thấy (bởi printf của tôi() - gỡ lỗi) rằng stdin-thread đã gọi closesocket() trên socket của nó, và tôi có thể thấy rằng thread chính là select() - ing trên socket được kết hợp (tức là đầu kia của socket- cặp), nhưng chọn() không bao giờ trả về vì nó nên ... và nếu nó trở lại, do một số lựa chọn ổ cắm khác sẵn sàng cho bất cứ điều gì, FD_ISSET (main_thread_socket_for_socket_pair, & readSet) trả về 0, như thể kết nối không đã đóng cửa. Tại thời điểm này, giả thuyết duy nhất tôi có là có một lỗi trong triển khai select() của Windows gây ra việc chọn chủ đề chính() không để ý rằng đầu kia của cặp socket đã bị đóng bởi stdin-thread. Có lời giải thích nào khác không? (Lưu ý rằng vấn đề này đã được báo cáo trong Windows 7 là tốt, mặc dù tôi chưa xem xét nó trên nền tảng đó)
Đó là một dự đoán rất tốt, nhưng tôi đã kiểm tra lại và chuỗi stdin không được khởi chạy cho đến sau khi CreateConnectedSocketPair() đã trả về thành công. Vì vậy, tôi không nghĩ rằng đó là vấn đề. –