2012-06-12 44 views
6

Tại nơi làm việc, tôi đã được giao nhiệm vụ triển khai máy chủ TCP như một phần của thiết bị nô lệ Modbus. Tôi đã thực hiện rất nhiều đọc cả ở đây trên trao đổi stack và trên internet nói chung (bao gồm cả tuyệt vời http://beej.us/guide/bgnet/) nhưng tôi đang đấu tranh với một vấn đề thiết kế. Tóm lại, thiết bị của tôi chỉ có thể chấp nhận 2 kết nối và trên mỗi kết nối sẽ là các yêu cầu modbus đến mà tôi phải xử lý trong vòng điều khiển chính của tôi và sau đó trả lời với trạng thái thành công hoặc lỗi. Tôi có những ý tưởng sau đây về cách thực hiện điều này.Viết máy chủ TCP đa luồng trên Linux

  1. Có một sợi listener tạo, liên kết, lắng nghe và chấp nhận kết nối, sau đó sinh ra một pthread mới để lắng nghe trên các kết nối dữ liệu đến và kết nối chặt chẽ sau một khoảng thời gian timeout nhàn rỗi. Nếu số lượng các chủ đề đang hoạt động hiện tại là 2, các kết nối mới sẽ được đóng ngay lập tức để đảm bảo chỉ có 2 được cho phép.

  2. Không phát sinh chủ đề mới từ chuỗi người nghe, thay vào đó hãy sử dụng select() để phát hiện các yêu cầu kết nối đến cũng như modem kết nối đến kết nối đang hoạt động (tương tự như cách tiếp cận trong hướng dẫn Beejs).

  3. Tạo 2 chuỗi trình nghe mỗi chuỗi tạo ra một ổ cắm (cùng IP và số cổng) có thể chặn trên các cuộc gọi accept(), sau đó đóng socket fd và xử lý kết nối. Ở đây tôi (có lẽ ngây thơ) giả định rằng điều này sẽ chỉ cho phép tối đa 2 kết nối mà tôi có thể giải quyết bằng cách sử dụng chặn đọc.

Tôi đã sử dụng C++ trong một thời gian dài nhưng tôi khá mới để phát triển Linux. Tôi thực sự hoan nghênh bất kỳ đề xuất nào về cách tiếp cận trên là tốt nhất (nếu có) và nếu sự thiếu kinh nghiệm của tôi với Linux có nghĩa là bất kỳ ý tưởng nào thực sự là xấu. Tôi muốn tránh fork() và dính vào pthreads khi các yêu cầu modbus đến sẽ được xếp hàng đợi và đọc một vòng lặp điều khiển chính định kỳ. Cảm ơn trước cho tất cả lời khuyên.

Trả lời

3

Giải pháp thay thế thứ ba sẽ không hoạt động, bạn chỉ có thể liên kết với địa chỉ cục bộ một lần.

Tôi có thể sử dụng giải pháp thay thế thứ hai của bạn, trừ khi bạn cần thực hiện nhiều quá trình xử lý trong trường hợp kết hợp của lựa chọn thay thế đầu tiên có thể hữu ích.

Sự kết hợp của hai giải pháp thay thế đầu tiên mà tôi đang nghĩ đến là có chuỗi chính (bắt đầu từ chương trình) tạo hai chuỗi công việc, sau đó thực hiện cuộc gọi accept để chờ kết nối mới . Khi một kết nối mới đến, hãy nói một trong các chủ đề để bắt đầu làm việc trên kết nối mới và quay trở lại để chặn trên accept. Khi kết nối thứ hai được chấp nhận, bạn yêu cầu thread khác làm việc trên kết nối đó. Nếu cả hai kết nối đã được mở, hoặc không chấp nhận cho đến khi một kết nối được đóng lại, hoặc chờ kết nối mới nhưng đóng chúng ngay lập tức.

+0

Tôi thích âm thanh này - vấn đề duy nhất là vòng lặp chính của tôi không được chặn. Nó phải xử lý và định kỳ xử lý các yêu cầu từ các luồng trình nghe. Với điều này trong tâm trí bạn nói tùy chọn 2. sẽ là tốt nhất? – mathematician1975

+0

@ mathematician1975 Bạn vẫn có thể sử dụng phương pháp của tôi, nhưng thay vì chặn trên 'accept' sử dụng ngắn hoặc không có thời gian chờ' select' (hoặc làm cho ổ cắm nghe không chặn và sử dụng 'accept' và kiểm tra' EAGAIN'/'EWOULDBLOCK ') để biết khi nào một kết nối có thể được chấp nhận. –

+0

Tôi nghĩ rằng với những hạn chế về thời gian của tôi, đây là giải pháp tốt nhất để tôi theo đuổi trong ngắn hạn. Cảm ơn lời khuyên của bạn. – mathematician1975

2

Vì bạn chỉ xử lý 2 kết nối, chuỗi cho mỗi kết nối là hoàn hảo cho loại ứng dụng này. Các phương pháp tiếp cận hướng đối tượng sử dụng I/O không chặn hoặc không đồng bộ sẽ tốt hơn nếu bạn cần mở rộng tới hàng nghìn kết nối. 2 chuỗi trình nghe có ý nghĩa, bạn không cần đóng fd chấp nhận. Chỉ cần trở lại để chấp nhận nó khi kết nối được hoàn thành. Trong thực tế, một biến thể là có ba chủ đề bị chặn làm chấp nhận. Nếu hai trong số các chủ đề đang chủ động xử lý các kết nối, thì thứ ba đặt lại kết nối mới được tạo ra (hoặc trả về phản hồi bận, bất kỳ điều gì thích hợp cho thiết bị của bạn).

Để có tất cả ba chuỗi chặn trên chấp nhận, bạn cần phải tạo chủ đề chính và liên kết ổ cắm của bạn trước khi khởi chạy ba luồng để thực hiện xử lý chấp nhận/xử lý của chúng.

man page for pthreads on Linux cho biết rằng chấp nhận là an toàn chỉ. (Phần nằm dưới các chức năng an toàn chủ đề liệt kê các chức năng không an toàn chỉ, hãy xem hình.)

+0

Bạn có nghĩa là tùy chọn 3 trong câu hỏi của tôi? – mathematician1975

+0

@ mathematician1975: vâng, tôi đã suy nghĩ một biến thể của tùy chọn 3, nhưng với ba chủ đề chấp nhận. – jxh

+0

Nhưng câu trả lời khác ở đây nói rằng tôi chỉ có thể ràng buộc một lần, trong đó quy tắc lựa chọn 3. ?? – mathematician1975

2

Tất cả các tùy chọn thiết kế mà bạn đề xuất không hướng đối tượng, và tất cả đều hướng về C hơn C++ . Nếu công việc của bạn cho phép bạn sử dụng boost, thì thư viện Boost.Asio thật tuyệt vời để tạo các máy chủ socket đơn giản (và phức tạp). Bạn có thể lấy gần như bất kỳ ví dụ nào của họ và mở rộng tầm thường để chỉ cho phép 2 kết nối đang hoạt động, đóng tất cả các kết nối khác ngay khi chúng được mở.

Tắt đầu, máy chủ HTTP đơn giản của chúng có thể được sửa đổi để thực hiện việc này bằng cách giữ bộ đếm tĩnh trong lớp kết nối (trong hàm tạo, hủy trong trình hủy) và khi tạo một kiểm tra mới đếm và quyết định có nên đóng kết nối không. Lớp kết nối cũng có thể tăng thêm :: asio :: deadline_timer để theo dõi thời gian chờ.

Điều này gần giống nhất với lựa chọn thiết kế đầu tiên của bạn, tăng có thể thực hiện việc này trong 1 chuỗi và trong nền có chức năng tương tự như select() (thường là epoll()). Nhưng đây là "cách C++", và theo ý kiến ​​của tôi, sử dụng select() và raw pthread s là cách C.

+0

Cảm ơn đề xuất này. Tôi hoàn toàn đồng ý với bạn về khía cạnh C++ và OO của nó. Tuy nhiên, với những hạn chế hiện tại về thời gian của tôi, tôi nghĩ rằng tôi sẽ phải theo đuổi các phương pháp tiếp cận API linux nguyên vì nó đã đưa tôi thời gian để làm quen với nó và cần phải có được một nguyên mẫu nhanh chóng. Tuy nhiên, một khi dự án được chấp nhận, tôi nghĩ rằng tôi chắc chắn sẽ ủng hộ cách tiếp cận này – mathematician1975

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