2013-05-22 9 views
9

मेरे पास localhost:8080 पर एक साधारण HTTP सेवा होस्ट करने वाला एक गो प्रोग्राम है, इसलिए मैं nginx को proxy_pass निर्देश के माध्यम से इसे होस्ट करने के लिए एक रिवर्स प्रॉक्सी के रूप में कनेक्ट कर सकता हूं मेरी साइट के अनुरोध का हिस्सा। यह सब बहुत अच्छा काम कर रहा है, कोई समस्या नहीं है।गो प्रोग्रामिंग भाषा में एक यूनिक्स डोमेन सॉकेट को विश्वसनीय रूप से अनलिंक कैसे करें (

मैं बेहतर सुरक्षा के लिए स्थानीय टीसीपी सॉकेट की बजाय यूनिक्स डोमेन सॉकेट पर HTTP सेवा होस्ट करने और टीसीपी के अनावश्यक प्रोटोकॉल ओवरहेड को कम करने के लिए गो प्रोग्राम को कनवर्ट करना चाहता हूं।

समस्या: समस्या यह है कि यूनिक्स डोमेन सॉकेट पुन: उपयोग नहीं किया जा सकता है एक बार वे bind() लिए कर रहे हैं, इस कार्यक्रम समाप्ति के बाद भी है। दूसरी बार (और हर बार बाद में) मैं गो प्रोग्राम चलाता हूं यह एक घातक त्रुटि "address already in use" से निकलता है।

सामान्य अभ्यास unlink() यूनिक्स डोमेन सॉकेट (यानी फ़ाइल को हटा दें) जब सर्वर बंद हो जाता है। हालांकि, यह गो में मुश्किल है। मेरा पहला प्रयास मेरे मुख्य func में defer कथन का उपयोग करना था (नीचे देखें), लेकिन अगर मैं CTRL-C जैसे सिग्नल के साथ प्रक्रिया को बाधित करता हूं तो यह दौड़ नहीं रहा है। मुझे लगता है कि यह उम्मीद की जा रही है। निराशाजनक, लेकिन अप्रत्याशित नहीं।

प्रश्न: वहाँ कैसे सॉकेट unlink() जब सर्वर प्रक्रिया बंद हो जाती है (या तो शान से या ungracefully) पर एक सबसे अच्छा अभ्यास है?

यहाँ मेरी func main() की बात यह है कि सर्वर संदर्भ के लिए सुन शुरू होता है:

// Create the HTTP server listening on the requested socket: 
l, err := net.Listen("unix", "/tmp/mysocket") 
if err != nil { 
    log.Fatal(err) 
} else { 
    // Unix sockets must be unlink()ed before being reused again. 
    // Unfortunately, this defer is not run when a signal is received, e.g. CTRL-C. 
    defer func() { 
     os.Remove("/tmp/mysocket") 
    }() 

    log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml))) 
} 
+0

http : //stackoverflow.com/questions/11268943/golang-is-it-possible-to-capture-a-ctrlc-sigterm-signal-and-run-a-cleanup-fu – thwd

+0

@ टॉम धन्यवाद। वह प्रश्न/उत्तर एक वर्ष पुराना है और गो अभी भी सुधार रहा है इसलिए मैं देखना चाहता था कि कुछ नया/बेहतर आया है या नहीं। –

+2

'ओ। रीमोव ("/ tmp/mysocket") पहले पंक्ति से पहले कोशिश करें, क्या यह काम कर रहा है? –

उत्तर

7

यहाँ पूर्ण समाधान मैं प्रयोग किया जाता है। मेरे प्रश्न में पोस्ट किया गया कोड स्पष्ट प्रदर्शन उद्देश्यों के लिए एक सरलीकृत संस्करण था।

// Create the socket to listen on: 
l, err := net.Listen(socketType, socketAddr) 
if err != nil { 
    log.Fatal(err) 
    return 
} 

// Unix sockets must be unlink()ed before being reused again. 

// Handle common process-killing signals so we can gracefully shut down: 
sigc := make(chan os.Signal, 1) 
signal.Notify(sigc, os.Interrupt, os.Kill, syscall.SIGTERM) 
go func(c chan os.Signal) { 
    // Wait for a SIGINT or SIGKILL: 
    sig := <-c 
    log.Printf("Caught signal %s: shutting down.", sig) 
    // Stop listening (and unlink the socket if unix type): 
    l.Close() 
    // And we're done: 
    os.Exit(0) 
}(sigc) 

// Start the HTTP server: 
log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml))) 

मुझे यकीन है कि यह अच्छा और प्रभावी गो कोड है जो गो लेखकों को गर्व करेगा। यह निश्चित रूप से मुझे ऐसा लगता है। यदि यह नहीं है, तो यह मेरे हिस्से पर शर्मनाक होगा। :)

किसी के लिए उत्सुकता के लिए, यह https://github.com/JamesDunne/go-index-html का हिस्सा है जो कुछ सरल सुविधाओं के साथ जेनरेटर सूचीबद्ध एक साधारण HTTP निर्देशिका है जो वेब सर्वर आपको बॉक्स से बाहर नहीं देता है।

+1

'l.Close() 'सॉकेट फ़ाइल को अनलिंक कर देगा, अगर श्रोता' यूनिक्स लिस्टनर 'प्रकार का है। 'ओ। रिमूव (सॉकेट एडडर)' अनावश्यक है। – Gvozden

2

आप सिग्नल हैंडलर के साथ अपना मुख्य func समाप्त कर सकते हैं और इसके बजाय अपने अन्य कार्यों के लिए अलग-अलग जाने के दिन नियमित रूप से चल सकते हैं। इस तरह, आप आस्थगित करें तंत्र का लाभ उठाने और सफाई से सभी (संकेत के आधार पर हो या नहीं) के बंद संभाल कर सकते हैं: आधुनिक जाओ

func main() { 
    // Create the HTTP server listening on the requested socket: 
    l, err := net.Listen("unix", "/tmp/mysocket") 
    if err != nil { 
     log.Fatal(err) 
     return 
    } 
    // Just work with defer here; this works as long as the signal handling 
    // happens in the main Go routine. 
    defer l.Close() 

    // Make sure the server does not block the main 
    go func() { 
     log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml))) 
    }() 


    // Use a buffered channel so we don't miss any signals 
    c := make(chan os.Signal, 1) 
    signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGTERM) 

    // Block until a signal is received. 
    s := <-c 
    fmt.Println("Got signal:", s) 

    // ...and exit, running all the defer statements 
} 
1

, तो आप उपयोग कर सकते हैं syscall.Unlink() - डॉक्स here:

import ( 
    "net" 
    "syscall" 
    ... 
) 

... 


socketpath := "/tmp/somesocket" 
// carry on with your socket creation: 
addr, err := net.ResolveUnixAddr("unixgram", socketpath) 
if err != nil { 
    return err; 
} 

// always remove the named socket from the fs if its there 
err = syscall.Unlink(socketpath) 
if err != nil { 
    // not really important if it fails 
    log.Error("Unlink()",err) 
} 

// carry on with socket bind() 
conn, err := net.ListenUnixgram("unixgram", addr); 
if err != nil { 
    return err; 
} 
संबंधित मुद्दे