2010-08-15 18 views
8

Có nhiều hơn một quá trình đọc từ một thiết bị nối tiếp (/ dev/ttyXX) làm cho nó để cả hai quá trình không thể có được tất cả các dữ liệu - dữ liệu sẽ được phân chia giữa chúng theo một cách nào đó. Tôi muốn viết một chương trình đọc từ một thiết bị nối tiếp, tạo ra một số cặp pty chính/phụ, và sau đó cho phép các chương trình được thực hiện để đọc từ thiết bị nối tiếp để đọc từ các pty để tất cả các quy trình đọc nhận dữ liệu từ thiết bị nối tiếp và có các pty hoạt động giống như thiết bị nối tiếp theo nghĩa là khi chúng bắt đầu đọc từ pty, chúng chỉ nhận được dữ liệu gần đây nhất. Nói cách khác, bạn sẽ không nhận được bất kỳ dữ liệu nào được viết trước khi bạn bắt đầu đọc (đó là kinh nghiệm của tôi rằng thiết bị/dev/ttyXX hoạt động hoặc ít nhất là máy đo gió RS-232 mà tôi đang đọc). Các ống được đặt tên có thể bắt chước các ngữ nghĩa này bằng cách bẫy SIGPIPE để xác định rằng không có trình đọc và do đó chúng ta có thể chọn không ghi vào đường ống được đặt tên cụ thể đó. Tuy nhiên, một số tệp nhị phân được viết để sử dụng thiết bị đầu cuối có thể không thành công khi nói đến các đường ống được đặt tên, như kiểm tra cho isatty() và điều kiện errno trên các cuộc gọi như tcsetattr() có thể gây ra các điều kiện không thành công. Chìa khóa ở đây là để có thể sử dụng các tệp nhị phân hiện có được viết cho một thiết bị đầu cuối. Vì vậy, nếu tôi có thể phát hiện khi bên nô lệ của pty được mở để đọc, điều này sẽ cho tôi gần như cùng ngữ nghĩa vì không có SIGPIPE trong trường hợp ống có tên. Tôi nhận thấy rằng HP-UX có TIOCTRAP như một lệnh ioctl() mà dường như làm chính xác những gì tôi muốn, nhưng thật đáng buồn là nó không có sẵn trên Linux.Làm thế nào tôi có thể phát hiện khi ai đó mở bên nô lệ của một pty (pseudo-terminal) trong Linux?

Tôi đã đọc tài liệu tham khảo trong nhiều ngày và số tùy chọn cho loại điều này thật đáng kinh ngạc. Câu trả lời có thể nằm trong cài đặt đầu cuối, hành vi chặn/không chặn, thiết lập kích thước bộ đệm ở đâu đó, các điều kiện được báo cáo từ poll()/select() hoặc kết hợp một số. Tôi không thể tìm thấy bất cứ điều gì, mặc dù. Tôi tự hỏi nếu có thể tôi cần phải viết trình điều khiển thiết bị của riêng mình, nhưng có vẻ như tôi có thể làm điều này mà không đi xa đến vậy.

Vì vậy, để làm rõ:
- Câu hỏi đặt ra là: Làm thế nào tôi có thể phát hiện khi ai đó mở bên nô lệ của một pty (pseudo-terminal) trong Linux?
- Tôi muốn một người đọc mở mặt nô lệ của pty để nhận dữ liệu được viết hoàn toàn sau khi người đọc mở pty (nếu quá trình đa văn bản của tôi chỉ ghi dữ liệu trong một thời gian trước khi người đọc mở bên nô lệ, dữ liệu sẽ đệm lên và cuối cùng người viết sẽ chặn và người đọc nô lệ, khi mở, sẽ ngay lập tức nhận được tất cả dữ liệu đệm - điều này là không mong muốn vì tôi muốn nó chỉ nhận dữ liệu được tạo ra trong vùng lân cận thời gian ngay lập tức)
- Nó phải là một pty, không phải là một ống, ổ cắm, vv, như isatty() và tcsetattr(), vv cần phải OK để các tệp nhị phân hiện có hoạt động

Trả lời

9

Lý do bạn không thể tìm thấy điều này là do không có tài liệu giao diện specif ically để cho phép nó. Tuy nhiên, có một thủ thuật cho phép bạn làm điều đó. Sau khi mở chủ pseudo-thiết bị đầu cuối (giả định ở đây là tập tin mô tả ptm), bạn mở và ngay lập tức đóng cửa phía nô lệ:

close(open(ptsname(ptm), O_RDWR | O_NOCTTY)); 

này đặt cờ HUP trên tổng thể tty. Bây giờ bạn có thăm dò ý kiến ​​cờ HUP thường xuyên với poll() (nói, bất cứ khi nào dữ liệu được lấy từ nguồn dữ liệu của bạn):

struct pollfd pfd = { .fd = ptm, .events = POLLHUP }; 
poll(&pfd, 1, 10 /* or other small timeout */); 

if (!(pfd.revents & POLLHUP)) 
{ 
    /* There is now a reader on the slave side */ 
} 

Nếu người đọc bao giờ đi xa, POLLHUP sẽ được thiết lập lại.

Trong trường hợp của bạn, có thể bạn thậm chí không cần nhớ từ một vòng lặp tới bước tiếp theo cho dù một pty cụ thể có trình đọc - chỉ cần chặn trên read() trên nguồn dữ liệu của bạn, khi dữ liệu có sẵn, đồng thời poll() tất cả các tty chủ của bạn và gửi dữ liệu đến bất kỳ người nào trong số họ không có số POLLHUP.

+0

Cảm ơn bạn đã giải thích. Tôi đã tìm thấy thủ thuật này trong mã nguồn để "socat", nhưng không nhận ra rằng tôi đã phải mở và sau đó đóng bên nô lệ. Ngay cả sau khi hiểu được mẹo, tôi vẫn có một số tập kéo tóc vì tôi đang sử dụng openpty() thay vì mở/dev/ptmx một cách rõ ràng, cho tôi một fd riêng biệt, mở fd cho các điểm và do đó tôi không thể có điều kiện HUP ban đầu. Gọi openpty() và sau đó đóng fd nô lệ trở về từ nó suffices. Cảm ơn lần nữa vì sự đáp ứng. Làm thế nào bạn tìm hiểu về tính năng không có giấy tờ? –

+0

Tôi nghĩ rằng tôi chỉ tìm thấy nó thông qua việc đăng (s) trên usenet. Câu hỏi này sẽ làm cho nó có thể google hơn cho người trong tương lai, mặc dù! – caf

3

Thêm đồng hồ inotify vào pty nô lệ và thăm dò ý kiến ​​trên đó. Bạn có thể nhận được một sự kiện inotify trên mở. Sau đó, bạn có thể thăm dò ý kiến ​​trên bộ mô tả tập tin inotify và bộ mô tả tệp pty chính. Bạn có thể nhận được một sự kiện inotify để mở (IN_OPEN). Điều này sẽ bỏ chặn cuộc thăm dò ý kiến ​​khi bên nô lệ được mở.

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