2009-11-17 18 views
22

और प्रश्न पर एक नज़र डालने के लिए धन्यवाद।PHP क्लाइंट और सी डेमॉन सर्वर के बीच आईपीसी कैसे करें?

पृष्ठभूमि
मैं कई मशीनों है कि लगातार एक बहुत ही कम समय सीमा में कई अंडे (300 तक) पीएचपी सांत्वना स्क्रिप्ट हैं। ये स्क्रिप्ट तेजी से चलती हैं (एक सेकंड से भी कम) और फिर बाहर निकलें। इन लिपियों के सभी एक बड़ी trie संरचना करने के लिए केवल पहुँच जो स्मृति में हर बार स्क्रिप्ट में से हर एक चलाता है लोड करने के लिए बहुत महंगा हो जाएगा पढ़ा है। सर्वर लिनक्स चलाता है।

मेरे समाधान
एक सी डेमॉन कि स्मृति में trie संरचना रहता है और PHP ग्राहकों से अनुरोध प्राप्त बनाएँ। यह प्रत्येक PHP क्लाइंट से अनुरोध प्राप्त करेगा, मेमोरी स्ट्रक्चर पर लुकअप करेगा और उत्तर के साथ जवाब देगा, PHP स्क्रिप्ट को उस काम से सहेजने से बचाएगा। दोनों अनुरोध और प्रतिक्रियाओं संक्षिप्त स्ट्रिंग (अब की तुलना में 20 वर्ण)

मेरे समस्या
मैं सी डेमॉन और अंतर प्रक्रिया संचार करने के लिए बहुत नया हूँ कर रहे हैं। बहुत से शोध के बाद, मैंने संदेशों को संदेश कतारों और यूनिक्स डोमेन सॉकेट तक सीमित कर दिया है। संदेश पंक्तियां पर्याप्त प्रतीत होती हैं क्योंकि मुझे लगता है कि (मैं गलत हो सकता हूं) कि वे डेमॉन के लिए सभी अनुरोधों को क्रमशः उत्तर देने के लिए कतारबद्ध करते हैं। यूनिक्स डोमेन सॉकेट का उपयोग करना आसान प्रतीत होता है, हालांकि। हालांकि, मेरे पास कई प्रश्न हैं जिनके जवाब मुझे नहीं मिल पाए हैं:

  1. PHP स्क्रिप्ट कैसे संदेश भेज सकता है और प्राप्त कर सकता है या डेमॉन के साथ संवाद करने के लिए यूनिक्स सॉकेट का उपयोग कैसे कर सकता है? इसके विपरीत सी डीमन किस ट्रैक प्रक्रिया को ट्रैक करने के लिए ट्रैक भेजता है?
  2. डेमॉन के अधिकांश उदाहरण मैं एक अनंत का उपयोग करते हुए एक सोने हालत के अंदर के साथ पाश को देखा है। मेरे डिमन को कई कनेक्शनों की सेवा करने की ज़रूरत है जो किसी भी समय आ सकती हैं, और प्रतिक्रिया विलंबता महत्वपूर्ण है। अगर नींद सो रही है तो PHP स्क्रिप्ट अनुरोध भेजता है तो डेमॉन प्रतिक्रिया कैसे करेगा? मैंने चुनाव और एपोल के बारे में पढ़ा है, क्या यह एक प्राप्त संदेश की प्रतीक्षा करने का सही तरीका होगा?
  3. प्रत्येक पीएचपी प्रक्रिया हमेशा एक अनुरोध भेज देंगे, और फिर एक प्रतिक्रिया प्राप्त करने के लिए इंतजार करेंगे। मुझे यकीन है कि अगर डेमॉन नीचे/उपलब्ध नहीं है, पीएचपी प्रक्रिया एक सेट अधिक से अधिक समय के लिए एक प्रतिक्रिया के लिए इंतजार करेंगे बनाने की जरूरत है, और अगर कोई जवाब नहीं प्राप्त होता है फांसी की परवाह किए बिना बजाय जारी रहेगा। क्या यह किया जा सकता है?

डेटा संरचना का वास्तविक लुकअप बहुत तेज़ है, मुझे किसी भी जटिल बहु-थ्रेडिंग या इसी तरह के समाधान की आवश्यकता नहीं है, क्योंकि मुझे लगता है कि फीफो तरीके से अनुरोधों को संभालने के लिए पर्याप्त होगा। मुझे इसे सरल बेवकूफ रखने की भी आवश्यकता है, क्योंकि यह एक मिशन महत्वपूर्ण सेवा है, और मैं इस प्रकार के कार्यक्रम के लिए बिल्कुल नया हूं। (मुझे पता है, लेकिन मैं वास्तव में इस के आसपास कोई रास्ता नहीं है, और सीखने का अनुभव बहुत अच्छा होगा)

मैं वास्तव में कोड के टुकड़े कि मेरे पास है कि विशिष्ट प्रश्नों पर कुछ प्रकाश डालने की सराहना करेंगे। गाइड और पॉइंटर्स के लिए लिंक जो कम स्तर के आईपीसी की इस अस्पष्ट दुनिया में मेरी समझ को आगे बढ़ाएंगे, उनका भी स्वागत है।

आपकी मदद के लिए धन्यवाद!


अद्यतन

यह जानते हुए भी बहुत कुछ अब से मैं इस सवाल पूछने का समय था, मैं सिर्फ दिलचस्पी है कि दोनों Thrift ढांचे और ZeroMQ दूर सार संक्षेप का एक शानदार काम कर किसी को बाहर बिंदु करना चाहता था हार्ड, सॉकेट-स्तरीय प्रोग्रामिंग। बहाव आपको सर्वर के लिए मचान भी मुफ्त में देता है!

वास्तव में, नेटवर्क सर्वर बनाने के सभी कड़ी मेहनत के लिए जाने के बजाय, आपको एक अच्छा एसिंक्रोनस सर्वर का उपयोग करके केवल एप्लिकेशन सर्वर कोड लिखने पर विचार करें जो पहले से ही आपके लिए समस्या हल कर चुका है। बेशक सर्वर जो एसिंक्रोनस आईओ का उपयोग करते हैं वे उन नेटवर्क अनुप्रयोगों के लिए बहुत अच्छे हैं जिन्हें गहन CPU प्रोसेसिंग (या अन्य ईवेंट लूप ब्लॉक) की आवश्यकता नहीं होती है।

पायथन के लिए उदाहरण: Twisted, gevent। मैं gevent पसंद करते हैं, और मैं टर्ननाडो शामिल नहीं है क्योंकि यह HTTP सर्वर पक्ष पर केंद्रित है।

रूबी के लिए उदाहरण: EventMachine

बेशक

, Node.js मूल रूप से एक async सर्वर आजकल के लिए डिफ़ॉल्ट विकल्प है।

यदि आप गहरे जाना चाहते हैं, तो C10k Problem, और Unix Network Programing पढ़ें।

+0

मतदान हाँ, डेमॉन होना चाहिए, और मुझे विश्वास है कि यूनिक्स तुम सब करने की है कुर्सियां ​​के साथ है सॉकेट पीएचपी में संकलित करने का समर्थन करते है .. लेकिन मुझे पूरी तरह से यकीन नहीं है – Earlz

उत्तर

4

मुझे संदेह है कि Thrift वह है जो आप चाहते हैं। आपको PHP < -thrift-> C++ < -> सी करने के लिए थोड़ा गोंद कोड लिखना होगा, लेकिन यह शायद स्वयं को रोल करने से अधिक मजबूत होगा।

+2

बहाव निश्चित रूप से आजकल उद्योग मानक है - http://wiki.apache.org/thrift/PoweredBy - और शुरुआत में इस उपयोग के लिए कल्पना की गई थी (PHP को सी डेमन्स को हुक अप करना)। यदि आप "सी डेमन्स और इंटर प्रोसेस संचार के लिए बहुत नए हैं" तो आपको निश्चित रूप से एक नज़र रखना चाहिए; यह आपके लिए एक अच्छा, तेज़ libevent- आधारित सी सर्वर बना देगा और PHP और C. – cce

+0

के बीच सभी क्रमबद्धता को संभालेगा। मैंने थ्रिफ्ट पर एक नज़र डाली, जो मेरे लिए नया था, और मुझे कहना होगा कि मैं प्रभावित हूं! ऐसा लगता है कि यह स्वचालित रूप से आईपीसी की सभी देखभाल के साथ एक महान डिमन उत्पन्न करता है और मुझे केवल वास्तविक कार्यक्षमता जोड़नी है! प्रभावशाली, धन्यवाद! –

+0

सहमत हैं, ज़ीरोक का आइस - zeroc.com एक और ग्राहक/सर्वर 'लाइब्रेरी' है जिसे आप बॉक्स से बाहर कर सकते हैं, जो आपको क्लाइंट और सर्वर घटक भी देता है। –

0

हालांकि मैंने इसे कभी भी कोशिश नहीं की है, memcached उचित PHP extension के साथ अधिकांश गंदे काम को खत्म करना चाहिए।

स्पष्टीकरण: मैं पूरी तरह से यह मान रहा था कि यदि आपने ऐसा किया है, तो आप त्रिभुज कुंजियों का उपयोग करके त्रिभुज की अलग-अलग पत्तियों को त्रिभुज कुंजियों का उपयोग करते हुए यादें में डाल देंगे। इस दृष्टिकोण की व्यवहार्यता और वांछनीयता, निश्चित रूप से, कई कारकों पर निर्भर करती है, पहले और सबसे महत्वपूर्ण डेटा स्रोत है।

+0

हर बार जब मैंने इसे मेमकैच से पुनर्प्राप्त किया, तो विशाल डेटा संरचना को क्रमबद्ध/अनसुलझा करने की लागत यही कारण है कि मैं इस अन्य समाधान को आजमा रहा हूं, लेकिन धन्यवाद! यह अंतिम समाधान हो सकता है जिसका मैं उपयोग करूंगा। –

+0

निर्भर करता है कि त्रिभुज कितना बड़ा है। Memcached एक मेग से बड़ा कुछ भी स्टोर नहीं करेगा। और फिर आपको प्रत्येक अनुरोध पर ऑब्जेक्ट को deserializing के उपर है। –

1

"समस्या" (शायद नहीं?) यह है कि एसआईएसवी एमक्यू पर निश्चित रूप से कई उपभोक्ता/उत्पादक हो सकते हैं। यद्यपि आप जो कर रहे हैं उसके लिए पूरी तरह से संभव है, यदि आपके पास जरूरी नहीं है कि निर्माता: एम उपभोक्ता को आवश्यकता हो: संसाधन मॉडल के लिए उपभोक्ता, आपके पास यहां एक अनुरोध/प्रतिक्रिया मॉडल है।

आप एसआईएसवी एमक्यू के साथ कुछ अजीब हैंगअप प्राप्त कर सकते हैं।

सबसे पहले, क्या आप सुनिश्चित हैं कि आईएनईटी सॉकेट आपके लिए पर्याप्त तेज़ नहीं हैं? यूनिक्स डोमेन सॉकेट का उपयोग कर एक त्वरित PHP उदाहरण http://us.php.net/socket-create-pair पर है (उदाहरण के लिए कोड उदाहरण के रूप में, PHP एंडपॉइंट के लिए सॉकेट_क्रेट() का उपयोग करें)।

2

आप PHP की साझा मेमोरी फ़ंक्शंस http://www.php.net/manual/en/book.shmop.php का उपयोग कर साझा मेमोरी में डेटा संरचना भी लोड कर सकते हैं।

ओह, यह दस्तावेज़ीकरण से स्पष्ट नहीं है लेकिन समन्वय चर shmop_open में $ key है। साझा की गई स्मृति तक पहुंच की आवश्यकता वाले प्रत्येक प्रक्रिया में एक ही $ कुंजी होनी चाहिए। इसलिए, एक प्रक्रिया साझा कुंजी को $ कुंजी के साथ बनाता है। तब अन्य प्रक्रियाएं उस साझा स्मृति तक पहुंच सकती हैं यदि वे एक ही $ कुंजी का उपयोग करते हैं। मेरा मानना ​​है कि आप $ कुंजी के लिए जो चाहें चुन सकते हैं।

0

स्क्रिप्ट के बीच आईपीसी पाइप का उपयोग करके आसानी से किया जा सकता है। जो एक बहुत ही सरल कार्यान्वयन करता है।

0

nanomsg को सादे सी में कोड किया गया है, इसलिए मुझे लगता है कि यह सी ++ में कोडित किए गए थ्रिफ्ट और ज़ीरोएमक्यू की तुलना में आपकी आवश्यकताओं के लिए बेहतर अनुकूल है।

इसमें PHP सहित कई भाषाओं के लिए wrappers है।

यहाँ एक काम कर उदाहरण NN_PAIR प्रोटोकॉल का उपयोग है: (आप NN_REQREP भी उपयोग कर सकते हैं)

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

यहाँ एक काम कर उदाहरण है जहां PHP स्क्रिप्ट एक सी डिमन के लिए अनुरोध भेजता है और फिर प्रतिक्रिया के लिए इंतजार कर रहा है। यह डेटाग्राम मोड में यूनिक्स डोमेन सॉकेट का उपयोग करता है, इसलिए यह तेज़ और सरल है।

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"); 
    } 

} 
संबंधित मुद्दे