2008-11-12 31 views
6
while (xxx) { 
    timeout.tv_sec=TIMEOUT; 
    timeout.tv_usec=0; 
    FD_ZERO(&set); 
    FD_SET(sd,&set); 

    switch (select(FD_SETSIZE,&set,NULL,NULL,&timeout)) 
    xxxxx 
} 

hoạt động tốt, tuy nhiênkhó chịu chọn() hành vi trong c

FD_ZERO(&set); 
FD_SET(sd,&set); 

while (xxx) { 
    timeout.tv_sec=TIMEOUT; 
    timeout.tv_usec=0; 

    switch (select(FD_SETSIZE,&set,NULL,NULL,&timeout)) 
    xxxxx 
} 

không. Nó hoạt động lần đầu tiên, nhưng lần sau nó chạy qua vòng lặp while nó sẽ bị hết thời gian chờ ngay cả khi ổ cắm sd nhận dữ liệu. Dường như với tôi là một sự lãng phí tài nguyên để trống rỗng và lấp đầy mọi lúc.

Bất kỳ ai có giải thích tốt về lý do này và thậm chí tốt hơn, có lẽ là đề xuất cách tránh nó?

+0

Tôi nghĩ rằng một số mã bạn đã thực hiện có thể quan trọng trong việc hiểu tại sao điều này hoạt động theo cách của nó. – SoapBox

Trả lời

12

chọn sửa đổi đối số của nó. Bạn thực sự phải khởi tạo lại nó mỗi lần.

Nếu bạn lo lắng về chi phí, chi phí xử lý FD_SET hoàn chỉnh trong hạt nhân có phần đáng kể hơn chi phí của FD_ZERO. Bạn chỉ muốn vượt qua tối đa fd của bạn, không phải FD_SETSZIZE, để giảm thiểu việc xử lý hạt nhân. Trong ví dụ của bạn:

switch (select((sd + 1),&set,NULL,NULL,&timeout)) 

Đối với một trường hợp phức tạp hơn với nhiều FDS, bạn thường kết thúc việc duy trì một biến tối đa:

FD_SET(sd,&set); 
if (sd > max) max = sd; 
... repeat many times... 

switch (select((max + 1),&set,NULL,NULL,&timeout)) 


Nếu bạn sẽ có một số lượng lớn các file descriptor và quan tâm về phí trên của schlepping chúng về, bạn nên xem xét một số lựa chọn thay thế để chọn(). Bạn không đề cập đến hệ điều hành bạn đang sử dụng, nhưng đối với hệ điều hành Unix-như có một vài ví dụ:

  • cho Linux, epoll()
  • cho FreeBSD/NetBSD/OpenBSD/MacOS X, kqueue ()
  • cho Solaris,/dev/thăm dò

các API là khác nhau, nhưng họ là tất cả về cơ bản một giao diện kernel stateful để duy trì một tập hợp các tập tin giới thiệu hoạt động. Khi một fd được thêm vào tập hợp, bạn sẽ được thông báo về các sự kiện trên fd đó mà không phải liên tục truyền lại nó.

+0

Cảm ơn bạn đã có câu trả lời tuyệt vời :) – deadcyclo

+1

Đối với một lựa chọn thay thế cho(), tại sao không bình chọn(), không giống như những gì bạn đề cập, giống nhau trên nhiều Unices? – bortzmeyer

+1

thăm dò ý kiến ​​() là tốt hơn trong đó bạn không phải reinitialize mảng của nó mỗi lần, nhưng bạn vẫn sao chép một cấu trúc lớn trong và ngoài của hạt nhân trên mỗi cuộc gọi. Nếu bạn có nhiều fds, các lựa chọn thay thế khác tránh được chi phí liên tục này bằng cách sửa đổi tập hợp fd trong hạt nhân. – DGentry

7

Đọc trang người dùng đã chọn. Tập hợp trả về chỉ là các bộ mô tả tập tin đã sẵn sàng để sử dụng. Bạn có nghĩa vụ phải sử dụng FD_ISSET để kiểm tra mỗi một nếu nó được thiết lập hay không.

Luôn khởi tạo fd_set ngay trước khi sử dụng.

+0

Tôi biết về FD_ISSET, nhưng tôi chưa bao gồm nó, bởi vì bây giờ tôi chỉ đang lắng nghe một ổ cắm (tôi sẽ bổ sung thêm các ổ cắm sau này). Vì vậy, có cách nào để có thể "sử dụng lại" mà không phải đặt fd_set trước? – deadcyclo

+0

Hành vi được ghi lại của select() bao gồm sửa đổi các bộ tại chỗ. Để trích dẫn The Pragmatic Programmer, "'select' không bị hỏng". – bk1e

0

Đó là cách chọn hoạt động. Nó hoạt động tốt nhất, và có ý nghĩa hơn, nếu bạn có nhiều hơn một ổ cắm. Đó là loại điểm: bạn đang lựa chọn trên nhiều ổ cắm. Nếu bạn muốn đọc từ một ổ cắm, chỉ cần đọc hoặc recv nó.

+1

Đọc không cung cấp thời gian chờ. Do đó việc sử dụng lựa chọn. + thực tế là tôi sẽ thêm một ổ cắm thứ hai sau trong giai đoạn phát triển. – deadcyclo

+0

Chỉ cần tiếp tục cung cấp các lựa chọn thay thế: nếu sd là ổ cắm, bạn có thể sử dụng setsockopt (sd, SO_RCVTIMEO, ...) để thêm thời gian chờ đọc.Tuy nhiên, nếu bạn định thêm một ổ cắm thứ hai sau đó, hãy chọn tùy chọn tốt hơn để theo đuổi. – DGentry

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