2016-12-14 11 views
7

पर पायथन मल्टीप्रोसेसिंग और नेटवर्किंग मैं एक टीसीपी 'इको सर्वर' को लागू करने की कोशिश कर रहा हूं। सरल सामग्री:विंडोज

  1. ग्राहक सर्वर को एक संदेश भेजता है।
  2. सर्वर संदेश
  3. सर्वर संदेश को अपरकेस में
  4. सर्वर
  5. ग्राहक प्रतिक्रिया प्रिंट ग्राहक के लिए संशोधित संदेश भेजता है धर्मान्तरित प्राप्त करता है।

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

मैं विंडोज 10 x64 और पायथन 3.5.2 x64 के साथ WinPython सूट का उपयोग कर रहा हूं।

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

क्या कोई यहां कुछ प्रकाश डाल सकता है? मुझे बताओ क्या गलत है? शायद पूरा विचार (साझा करना सॉकेट) खराब है ... और यदि ऐसा है, तो कृपया मुझे बताएं कि मैं अपना प्रारंभिक उद्देश्य कैसे प्राप्त कर सकता हूं: मेरे सर्वर को सक्रिय रूप से एक साथ (विंडोज़ पर) एकाधिक ग्राहकों को संभालने में सक्षम बनाता है (बताएं नहीं मुझे थ्रेडिंग के बारे में, हम सभी जानते हैं कि अजगर का धागा इसे काट नहीं देगा ¬¬)

यह भी ध्यान देने योग्य है कि डीबग फ़ंक्शन द्वारा कोई भी फाइल नहीं बनाई गई है। कोई भी प्रक्रिया इसे चलाने के लिए पर्याप्त समय तक नहीं रहती, मुझे विश्वास है।

अपने सर्वर कोड के विशिष्ट निर्गम (रन के बीच फर्क सिर्फ इतना प्रक्रिया संख्या है):

Server is running... 
Degree of parallelism: 4 
Socket created. 
Socket bount to: ('', 0) 
Process 3604 is alive: True 
Process 5188 is alive: True 
Process 6800 is alive: True 
Process 2844 is alive: True 

Press ctrl+c to kill all processes. 

Process 3604 is alive: False 
Process 3604 exit code: 1 
Process 5188 is alive: False 
Process 5188 exit code: 1 
Process 6800 is alive: False 
Process 6800 exit code: 1 
Process 2844 is alive: False 
Process 2844 exit code: 1 
The children died... 
Why god? 
WHYYyyyyy!!?!?!? 

सर्वर कोड:

# Imports 
import socket 
import packet 
import sys 
import os 
from time import sleep 
import multiprocessing as mp 
import pickle 
import io 

# Constants 
DEGREE_OF_PARALLELISM = 4 
DEFAULT_HOST = "" 
DEFAULT_PORT = 0 

def _parse_cmd_line_args(): 
    arguments = sys.argv 
    if len(arguments) == 1: 
     return DEFAULT_HOST, DEFAULT_PORT 
    else: 
     raise NotImplemented() 

def debug(data): 
    pid = os.getpid() 
    with open('C:\\Users\\Trauer\\Desktop\\debug\\'+str(pid)+'.txt', mode='a', 
       encoding='utf8') as file: 
     file.write(str(data) + '\n') 

def handle_connection(client): 
    client_data = client.recv(packet.MAX_PACKET_SIZE_BYTES) 
    debug('received data from client: ' + str(len(client_data))) 
    response = client_data.upper() 
    client.send(response)  
    debug('sent data from client: ' + str(response)) 

def listen(picklez):  
    debug('started listen function') 

    pid = os.getpid() 
    server_socket = pickle.loads(picklez) 
    debug('acquired socket') 

    while True: 
     debug('Sub process {0} is waiting for connection...'.format(str(pid))) 

     client, address = server_socket.accept() 
     debug('Sub process {0} accepted connection {1}'.format(str(pid), 
       str(client))) 

     handle_connection(client)   
     client.close() 
     debug('Sub process {0} finished handling connection {1}'. 
       format(str(pid),str(client))) 

if __name__ == "__main__":  
# Since most python interpreters have a GIL, multithreading won't cut 
# it... Oughta bust out some process, yo! 
    host_port = _parse_cmd_line_args() 
    print('Server is running...') 
    print('Degree of parallelism: ' + str(DEGREE_OF_PARALLELISM)) 

    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    print('Socket created.') 

    server_socket.bind(host_port) 
    server_socket.listen(DEGREE_OF_PARALLELISM) 
    print('Socket bount to: ' + str(host_port))   

    buffer = io.BytesIO() 
    mp.reduction.ForkingPickler(buffer).dump(server_socket) 
    picklez = buffer.getvalue() 

    children = [] 
    for i in range(DEGREE_OF_PARALLELISM):   
     child_process = mp.Process(target=listen, args=(picklez,)) 
     child_process.daemon = True 
     child_process.start() 
     children.append(child_process) 

     while not child_process.pid: 
      sleep(.25) 

     print('Process {0} is alive: {1}'.format(str(child_process.pid), 
       str(child_process.is_alive())))  
    print()  

    kids_are_alive = True 
    while kids_are_alive: 
     print('Press ctrl+c to kill all processes.\n') 
     sleep(1) 

     exit_codes = [] 
     for child_process in children: 
      print('Process {0} is alive: {1}'.format(str(child_process.pid), 
       str(child_process.is_alive()))) 
      print('Process {0} exit code: {1}'.format(str(child_process.pid), 
       str(child_process.exitcode))) 
      exit_codes.append(child_process.exitcode) 

     if all(exit_codes): 
      # Why do they die so young? :(
      print('The children died...') 
      print('Why god?') 
      print('WHYYyyyyy!!?!?!?') 
      kids_are_alive = False 

संपादित करें: "सुन" के हस्ताक्षर तय । मेरी प्रक्रियाएं अभी भी तुरंत मर जाती हैं।

संपादित 2: उपयोगकर्ता सेमीिडी ने इंगित किया कि यह कोड लिनक्स पर काम करता है; तो मेरा सवाल है: मैं विंडोज पर यह काम कैसे कर सकता हूं?

+1

मल्टीप्रोसेसिंग स्वचालित रूप से बाल प्रक्रियाओं में सॉकेट पास करने से संभालती है। विंडोज कार्यान्वयन सॉकेट 'शेयर' विधि और 'सेशेयर' फ़ंक्शन का उपयोग करता है। – eryksun

+1

मुख्य प्रक्रिया में 'स्वीकार करें() 'को कॉल करें और एक साझा' multiprocessing.Queue' का उपयोग करके परिणामी '(conn, addr)' tuple को एक कार्यकर्ता को पास करें। – eryksun

+0

कोई बदलाव नहीं, eryksun। मेरी प्रक्रियाएं अभी भी मर जाती हैं। – Trauer

उत्तर

3

आप सीधे बच्चे की प्रक्रिया में सॉकेट पास कर सकते हैं।

class DupSocket(object): 
    '''Picklable wrapper for a socket.''' 
    def __init__(self, sock): 
     new_sock = sock.dup() 
     def send(conn, pid): 
      share = new_sock.share(pid) 
      conn.send_bytes(share) 
     self._id = _resource_sharer.register(send, new_sock.close) 

    def detach(self): 
     '''Get the socket. This should only be called once.''' 
     with _resource_sharer.get_connection(self._id) as conn: 
      share = conn.recv_bytes() 
      return socket.fromshare(share) 

यह कहता है विंडोज सॉकेट share विधि है, जो WSADuplicateSocket कॉल करने से प्रोटोकॉल की जानकारी बफर रिटर्न: बहु इस के लिए एक कमी है, जिसके लिए विंडोज कार्यान्वयन multiprocessing.resource_sharer से निम्नलिखित DupSocket क्लास का उपयोग पंजीकृत करता है। यह इस प्रक्रिया को बाल प्रक्रिया के संबंध में भेजने के लिए संसाधन शेयरर के साथ पंजीकृत है। बदले में बच्चे detach पर कॉल करता है, जो प्रोटोकॉल जानकारी बफर प्राप्त करता है और सॉकेट को socket.fromshare के माध्यम से पुनर्निर्मित करता है।

यह सीधे आपकी समस्या से संबंधित नहीं है, लेकिन मैं सुझाव है कि आप सर्वर के बजाय मुख्य प्रक्रिया है, जो (पायथन के socketserver.ForkingTCPServer मॉड्यूल में उदा) जिस तरह से यह आम तौर पर किया जाता है में accept कॉल करने के लिए नया स्वरूप। परिणामी (conn, address)multiprocessing.Queue पर पहले उपलब्ध कार्यकर्ता को टुपल करें, जिसे प्रक्रिया पूल के सभी श्रमिकों द्वारा साझा किया जाता है। या के साथ multiprocessing.Pool का उपयोग करने पर विचार करें।

+0

मैं देखता हूं। [यह] (http://pastebin.com/uRjCBuaD) दृष्टिकोण के बारे में क्या, क्या यह वैध है? – Trauer

+0

मैंने यह जांच नहीं की है कि सुनवाई सॉकेट की दूसरी प्रक्रिया में कॉपी होने पर बैकलॉग कैसे संभाला जाता है। यदि प्रत्येक प्रति का अपना बैकलॉग होता है, तो शायद यह नहीं है कि आप क्या चाहते हैं। – eryksun

+0

मैं देखता हूं। आखिरी सवाल और मैं आपको परेशान करना बंद कर देता हूं, हे। क्या आप जानते हैं कि मुझे इसके बारे में कुछ दस्तावेज कहां मिल सकता है? – Trauer

0

def listen() लक्ष्य/अपने बच्चे प्रक्रियाओं के लिए शुरू किसी भी तर्क नहीं ले करता है, लेकिन आप एक तर्क args=(picklez,) बच्चे प्रक्रिया के रूप में धारावाहिक सॉकेट प्रदान कर रहे हैं इस बच्चे प्रक्रिया और बाहर निकलने के तुरंत में एक अपवाद का कारण होगा।

TypeError: listen() takes no arguments (1 given) 

def listen(picklez) समस्या का समाधान करना चाहिए इस के लिए अपने बच्चे की प्रक्रिया का लक्ष्य के लिए एक तर्क प्रदान करेगा।

+0

दरअसल, मूल रूप से पोस्ट किया गया फ़ंक्शन पूरा नहीं हुआ था। मैंने यहां एक अपूर्ण/गलत कोड पोस्ट किया है। सही हस्ताक्षर सुनो (picklez) है। मेरा मुद्दा है: दुख की बात यह समस्या नहीं है; मूल कोड में सही हस्ताक्षर है लेकिन मेरे बच्चे प्रक्रियाएं तुरंत मर जाती हैं, लेकिन उत्तर के लिए धन्यवाद। – Trauer

+0

सख्ती से बोलने के लिए 'स्वीकृति' को विभिन्न प्रक्रियाओं के उपयोग के बीच लॉक किया जाना चाहिए और कोड सॉकेट – cmidi

+0

को क्रमबद्ध किए बिना भी लिनक्स पर्यावरण पर काम कर रहा है, मुझे इस बारे में डर था ... मुझे लगा कि यह एक विंडोज़ जटिलता थी। मैं इस जानकारी को अपने quesiton में जोड़ दूंगा। धन्यवाद cmidi। – Trauer