2009-11-17 39 views
22

và cảm ơn bạn đã xem câu hỏi.Làm thế nào để IPC giữa các máy khách PHP và máy chủ C Daemon?

Nền
Tôi có một số máy liên tục sinh ra nhiều kịch bản lệnh PHP (lên đến 300) trong một khung thời gian rất ngắn. Các tập lệnh này chạy nhanh (ít hơn một giây) và sau đó thoát. Tất cả các kịch bản này chỉ cần đọc quyền truy cập vào cấu trúc trie lớn sẽ rất tốn kém để tải vào bộ nhớ mỗi khi mỗi một tập lệnh chạy. Máy chủ chạy Linux.

Giải pháp của tôi
Tạo C daemon giữ cấu trúc bộ nhớ trong bộ nhớ và nhận yêu cầu từ máy khách PHP. Nó sẽ nhận được yêu cầu từ tất cả các máy khách PHP, thực hiện tra cứu cấu trúc bộ nhớ và trả lời với câu trả lời, lưu các tập lệnh PHP khỏi thực hiện công việc đó. Cả hai yêu cầu và phản ứng là chuỗi ngắn (không quá 20 ký tự)

Vấn đề của tôi
Tôi rất mới để daemon C và thông tin liên lạc quá trình liên. Sau nhiều nghiên cứu, tôi đã thu hẹp các lựa chọn xuống Message Queues và các ổ cắm miền Unix. Hàng đợi tin nhắn có vẻ thích hợp bởi vì tôi nghĩ rằng (tôi có thể sai) rằng họ xếp hàng tất cả các yêu cầu cho daemon để trả lời chúng một cách thẳng thắn. Tuy nhiên, các ổ cắm miền Unix dường như dễ sử dụng hơn. Tuy nhiên, tôi có nhiều câu hỏi khác nhau mà tôi không thể tìm thấy câu trả lời cho:

  1. Làm thế nào một tập lệnh PHP gửi và nhận tin nhắn hoặc sử dụng ổ cắm UNIX để giao tiếp với daemon? Ngược lại, làm thế nào để C daemon theo dõi quá trình PHP mà nó phải gửi trả lời?
  2. Hầu hết các ví dụ về daemon tôi đã thấy sử dụng vòng lặp vô hạn trong khi có trạng thái ngủ bên trong. Daemon của tôi cần phục vụ nhiều kết nối có thể đến bất cứ lúc nào và độ trễ phản hồi là rất quan trọng. Daemon sẽ phản ứng như thế nào nếu kịch bản lệnh PHP gửi một yêu cầu trong khi nó đang ngủ? Tôi đã đọc về thăm dò ý kiến ​​và epoll, đây có phải là cách chính xác để chờ tin nhắn nhận được không?
  3. Mỗi quy trình PHP sẽ luôn gửi một yêu cầu, và sau đó sẽ đợi để nhận phản hồi. Tôi cần đảm bảo rằng nếu daemon bị hỏng/không có sẵn, quá trình PHP sẽ chờ phản hồi trong một khoảng thời gian tối đa đã đặt và nếu không nhận được câu trả lời nào sẽ tiếp tục bất kể thay vì treo. Điều này có thể được thực hiện?

Tra cứu cơ cấu dữ liệu thực sự rất nhanh, tôi không cần bất kỳ giải pháp đa luồng phức tạp hoặc giải pháp tương tự nào, vì tôi tin rằng việc xử lý yêu cầu theo cách FIFO sẽ là đủ. Tôi cũng cần phải giữ nó đơn giản ngu ngốc, vì đây là một dịch vụ quan trọng nhiệm vụ, và tôi khá mới đối với loại chương trình này. (Tôi biết, nhưng tôi thực sự không có cách nào để giải quyết vấn đề này và trải nghiệm học tập sẽ tuyệt vời)

Tôi thực sự đánh giá cao các đoạn mã chiếu sáng một số câu hỏi cụ thể mà tôi có. Liên kết đến hướng dẫn và con trỏ sẽ tiếp tục hiểu biết của tôi vào thế giới âm u này của IPC cấp thấp cũng được hoan nghênh.

Cảm ơn sự giúp đỡ của bạn!


Cập nhật

Biết nhiều hơn bây giờ hơn là tôi đã làm tại thời điểm đặt câu hỏi này, tôi chỉ muốn chỉ ra cho bất kỳ ai quan tâm rằng cả hai khuôn khổ ThriftZeroMQ làm một công việc tuyệt vời của abstracting đi chương trình cấp ổ cứng. Tiết kiệm thậm chí còn cung cấp cho bạn giàn giáo cho máy chủ miễn phí!

Trong thực tế, thay vì đi đến tất cả công việc khó khăn của việc xây dựng một máy chủ mạng, hãy xem xét chỉ viết cho bạn mã máy chủ ứng dụng bằng máy chủ không đồng bộ tốt đã giải quyết được sự cố cho bạn. Tất nhiên các máy chủ sử dụng IO không đồng bộ là tuyệt vời cho các ứng dụng mạng không yêu cầu xử lý CPU chuyên sâu (hoặc các khối vòng lặp sự kiện khác).

Ví dụ về python: Twisted, gevent. Tôi thích gevent, và tôi không bao gồm lốc xoáy vì nó tập trung vào phía máy chủ HTTP.

Ví dụ cho Ruby: EventMachine

Tất nhiên, Node.js về cơ bản là lựa chọn mặc định cho một máy chủ async hiện nay.

Nếu bạn muốn đi sâu hơn, hãy đọc C10k ProblemUnix Network Programing.

+0

Vâng, daemon nên bỏ phiếu, và tôi tin rằng với unix socket tất cả các bạn phải làm là đã socket hỗ trợ biên dịch vào PHP .. nhưng tôi không hoàn toàn chắc chắn – Earlz

Trả lời

4

Tôi nghi ngờ Thrift là thứ bạn muốn. Bạn sẽ phải viết một mã keo nhỏ để làm PHP < -ri-> C++ < -> C, nhưng điều đó có lẽ sẽ mạnh mẽ hơn so với việc cuộn của riêng bạn.

+2

Tiết kiệm chắc chắn là tiêu chuẩn công nghiệp hiện nay - http://wiki.apache.org/thrift/PoweredBy - và ban đầu được hình thành cho chính xác việc sử dụng này (hooking lên PHP để C daemons). Nếu bạn "rất mới với C daemons và liên lạc quá trình liên", bạn chắc chắn nên xem xét; nó sẽ làm cho một máy chủ C dựa trên lib tốt đẹp và nhanh chóng cho bạn và xử lý tất cả sự tuần tự hóa giữa PHP và C. – cce

+0

Tôi đã xem Thrift, điều mới mẻ đối với tôi, và tôi phải nói rằng tôi rất ấn tượng! Nó có vẻ như nó tự động tạo ra một daemon tuyệt vời với tất cả các IPC được chăm sóc và tôi chỉ phải thêm các chức năng thực tế! Ấn tượng, cảm ơn! –

+0

Đồng ý, ZeroC's Ice - zeroc.com là một thư viện máy khách/máy chủ 'khác mà bạn có thể sử dụng ngoài hộp, cung cấp cho bạn các thành phần máy khách và máy chủ. –

0

Mặc dù tôi chưa bao giờ thử nó, memcached cùng với PHP extension thích hợp phải loại bỏ hầu hết công việc grunt.

Làm rõ: Tôi đã ngầm giả định rằng nếu bạn đã làm điều này, bạn sẽ đặt các lá riêng lẻ của bộ ba vào memcache bằng cách sử dụng các phím phẳng, bỏ qua trie. Tính khả thi và mong muốn của phương pháp này, tất nhiên, phụ thuộc vào nhiều yếu tố, đầu tiên và quan trọng nhất là nguồn dữ liệu.

+0

Chỉ cần chi phí serializing/unserializing cấu trúc dữ liệu khổng lồ mỗi khi tôi lấy nó từ Memcached là lý do tôi đang cố gắng ra giải pháp này, nhưng cảm ơn! Nó có thể là giải pháp cuối cùng tôi sẽ sử dụng. –

+0

Phụ thuộc vào độ lớn của trie. Memcached sẽ không lưu trữ bất cứ điều gì lớn hơn một meg. Và sau đó bạn đã có các chi phí của deserializing các đối tượng trên mọi yêu cầu. –

1

"Vấn đề" (có thể không?) Là chắc chắn có thể có nhiều người tiêu dùng/nhà sản xuất trên SysV MQ. Mặc dù hoàn toàn có thể cho những gì bạn đang làm nếu bạn không nhất thiết phải có một m: n cần về nhà sản xuất: người tiêu dùng cho mô hình tài nguyên, bạn có một mô hình yêu cầu/phản hồi ở đây.

Bạn có thể gặp một số sự cố treo cổ lạ với SysV MQ.

Trước tiên, bạn có chắc chắn rằng các ổ cắm INET không đủ nhanh cho bạn? Một ví dụ PHP nhanh chóng bằng cách sử dụng ổ cắm miền unix là http://us.php.net/socket-create-pair (giống như ví dụ mã của khóa học, sử dụng socket_create() cho điểm cuối PHP).

2

Bạn cũng có thể tải cấu trúc dữ liệu vào bộ nhớ dùng chung bằng các chức năng bộ nhớ dùng chung của PHP http://www.php.net/manual/en/book.shmop.php.

Ồ, không rõ ràng từ tài liệu nhưng biến điều phối là $ key trong shmop_open. Mọi quá trình cần truy cập vào bộ nhớ dùng chung đều phải có cùng $ key. Vì vậy, một quá trình tạo bộ nhớ dùng chung với khóa $. Các quy trình khác sau đó có thể truy cập bộ nhớ chia sẻ đó nếu chúng sử dụng cùng một khóa $. Tôi tin rằng bạn có thể chọn bất cứ điều gì bạn thích cho $ key.

0

IPC giữa tập lệnh có thể được thực hiện dễ dàng bằng cách sử dụng Pipes. Mà làm cho một thực hiện đơn giản nhiều.

0

nanomsg được mã hóa bằng chữ C nên tôi đoán nó phù hợp hơn với nhu cầu của bạn so với Tiết kiệm và ZeroMQ được mã hóa bằng C++.

Nó có wrappers cho nhiều ngôn ngữ bao gồm PHP.

Dưới đây là một ví dụ làm việc bằng cách sử dụng giao thức NN_PAIR: (bạn có thể sử dụng NN_REQREP quá)

client.php

<?php 

$sock = new Nanomsg(NanoMsg::AF_SP, NanoMsg::NN_PAIR); 

$sock->connect('ipc:///tmp/myserver.ipc'); 

$sock->send('Hello World!', 0); 

$sock->setOption(NanoMsg::NN_SOL_SOCKET, NanoMsg::NN_RCVTIMEO, 1000); 

$data = $sock->recv(0, 0); 

echo "received: " . $data . "\n"; 

?> 

server.c

#include <stdio.h> 
#include <string.h> 
#include <nanomsg/nn.h> 
#include <nanomsg/pair.h> 

#define address "ipc:///tmp/myserver.ipc" 

int main() { 
    unsigned char *buf = NULL; 
    int result; 
    int sock = nn_socket(AF_SP, NN_PAIR); 
    if (sock < 0) puts("nn_socket failed"); 

    if (nn_bind(sock, address) < 0) puts("bind failed"); 

    while ((result = nn_recv(sock, &buf, NN_MSG, 0)) > 0) { 
    int i, size = strlen(buf) + 1; // includes null terminator 
    printf("RECEIVED \"%s\"\n", buf); 
    for (i = 0; buf[i] != 0; i++) 
     buf[i] = toupper(buf[i]); 
    nn_send(sock, buf, size, 0); 
    nn_freemsg(buf); 
    } 
    nn_shutdown(sock, 0); 
    return result; 
} 
0

Dưới đây là một ví dụ làm việc nơi tập lệnh php gửi yêu cầu tới một trình nền C và sau đó chờ phản hồi. Nó sử dụng các ổ cắm miền Unix trong chế độ datagram để nó nhanh và đơn giản.

client.php

<?php 

do { 
    $file = sys_get_temp_dir() . '/' . uniqid('client', true) . '.sock'; 
} while (file_exists($file)); 

$socket = socket_create(AF_UNIX, SOCK_DGRAM, 0); 

if (socket_bind($socket, $file) === false) { 
    echo "bind failed"; 
} 

socket_sendto($socket, "Hello World!", 12, 0, "/tmp/myserver.sock", 0); 

if (socket_recvfrom($socket, $buf, 64 * 1024, 0, $source) === false) { 
    echo "recv_from failed"; 
} 
echo "received: [" . $buf . "] from: [" . $source . "]\n"; 

socket_close($socket); 
unlink($file); 
?> 

server.c

#include <stdio.h> 
#include <sys/un.h> 
#include <sys/socket.h> 

#define SOCKET_FILE "/tmp/myserver.sock" 
#define BUF_SIZE 64 * 1024 

int main() { 
    struct sockaddr_un server_address = {AF_UNIX, SOCKET_FILE}; 

    int sock = socket(AF_UNIX, SOCK_DGRAM, 0); 
    if (sock <= 0) { 
     perror("socket creation failed"); 
     return 1; 
    } 

    unlink(SOCKET_FILE); 

    if (bind(sock, (const struct sockaddr *) &server_address, sizeof(server_address)) < 0) { 
     perror("bind failed"); 
     close(sock); 
     return 1; 
    } 

    while (1) { 
    struct sockaddr_un client_address; 
    int i, numBytes, len = sizeof(struct sockaddr_un); 
    char buf[BUF_SIZE]; 

    numBytes = recvfrom(sock, buf, BUF_SIZE, 0, (struct sockaddr *) &client_address, &len); 
    if (numBytes == -1) { 
     puts("recvfrom failed"); 
     return 1; 
    } 

    printf("Server received %d bytes from %s\n", numBytes, client_address.sun_path); 

    for (i = 0; i < numBytes; i++) 
     buf[i] = toupper((unsigned char) buf[i]); 

    if (sendto(sock, buf, numBytes, 0, (struct sockaddr *) &client_address, len) != numBytes) 
     puts("sendto failed"); 
    } 

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