2014-06-12 12 views
22

मैं रास्पबेरी पाई पर अपना स्वयं का http सर्वर चला रहा हूं। समस्या तब होती है जब मैं प्रोग्राम को रोकता हूं और इसे पुनरारंभ करता हूं, पोर्ट अब उपलब्ध नहीं है। कई अनुरोध प्राप्त करते समय कभी-कभी मुझे एक ही समस्या मिलती है।
मैं SO_REUSEADDR का उपयोग करना चाहता हूं ताकि त्रुटि होने पर भी मैं पोर्ट का उपयोग कर सकूं लेकिन इसे स्थापित करने में कोई भाग्य नहीं है। नीचे मेरा कोड है।
मुझे जो त्रुटि मिलती है वह है "बाध्यकारी पर त्रुटि: पता पहले से उपयोग में है"।मैं सेटॉकोपट (SO_REUSEADDR) का उपयोग कैसे करूं?

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 

void error(const char *msg) 
{ 
    perror(msg); 
    exit(1); 
} 

int main(int argc, char *argv[]) 
{ 
    printf("Starting Listener\n"); 
    int sockfd, newsockfd, portno; 
    socklen_t clilen; 
    char buffer[256]; 
    struct sockaddr_in serv_addr, cli_addr; 
    int n; 
    if (argc < 2) { 
     fprintf(stderr,"ERROR, no port provided\n"); 
     exit(1); 
    } 
    sockfd = socket(AF_INET, SOCK_STREAM, 0); 
    if (sockfd < 0) 
     error("ERROR opening socket"); 
    bzero((char *) &serv_addr, sizeof(serv_addr)); 
    portno = atoi(argv[1]); 
    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_addr.s_addr = INADDR_ANY; 
    serv_addr.sin_port = htons(portno); 
    if (bind(sockfd, (struct sockaddr *) &serv_addr, 
       sizeof(serv_addr)) < 0) 
       error("ERROR on binding"); 

    printf("about to listen\n"); 
    listen(sockfd,5); 
    printf("finished listening\n"); 
    clilen = sizeof(cli_addr); 
    printf("About to accept\n"); 

    int i; 
    for(i=0; i<100; i++){ 
     newsockfd = accept(sockfd, 
       (struct sockaddr *) &cli_addr, 
       &clilen); 

     if (newsockfd < 0) 
      error("ERROR on accept"); 
     bzero(buffer,256); 
     n = read(newsockfd,buffer,255); 
     if (n < 0) error("ERROR reading from socket"); 
     printf("Here is the message: %s\n",buffer); 
     n = write(newsockfd,"I got your message",18); 
     if (n < 0) error("ERROR writing to socket"); 
     close(newsockfd); 
    } 
    close(sockfd); 
    return 0; 
} 

उत्तर

48

के बाद:

sockfd = socket(AF_INET, SOCK_STREAM, 0); 
if (sockfd < 0) 
    error("ERROR opening socket"); 

आप (मानक C99 यौगिक litteral समर्थन के साथ) जोड़ सकते हैं:

if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int)) < 0) 
    error("setsockopt(SO_REUSEADDR) failed"); 

या:

int enable = 1; 
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) 
    error("setsockopt(SO_REUSEADDR) failed"); 
+0

मैं दोनों की कोशिश की और कार्यक्रम की मौत हो गई है और इसे वापस प्रारंभ करने के बाद ही परिणाम मिला है। यह त्रुटि है: बाइंडिंग बाध्यकारी पर त्रुटि: पता पहले से ही उपयोग में है सुनने के बारे में सुनना – user3735849

+0

स्वीकार करने के बारे में यदि आप प्रोग्राम को कठिन तरीके से मारते हैं तो यह ठीक से काम नहीं करेगा। आपको एक साफ निकास करना है। – Chnossos

+5

SO_REUSEADDR/SO_REUSEPORT का उद्देश्य बंदरगाह का पुन: उपयोग करने की अनुमति देना है भले ही प्रक्रिया क्रैश हो या मार डाला जाए। – mpromonet

22

libc रिहाई यह पर निर्भर करता है SO_RE दोनों सेट करने के लिए आवश्यक हो सकता है USEADDR और SO_REUSEPORT सॉकेट विकल्प socket(7) दस्तावेज में बताया गया है:

SO_REUSEPORT (since Linux 3.9) 
      Permits multiple AF_INET or AF_INET6 sockets to be bound to an 
      identical socket address. This option must be set on each 
      socket (including the first socket) prior to calling bind(2) 
      on the socket. To prevent port hijacking, all of the 
      processes binding to the same address must have the same 
      effective UID. This option can be employed with both TCP and 
      UDP sockets. 

इस सॉकेट विकल्प कर्नेल 3.9 और रास्पबेरी उपयोग 3.12.x के साथ प्रकट होता है, यह SO_REUSEPORT स्थापित करने के लिए की आवश्यकता होगी।

आप सेट कर सकते शोध करे दो विकल्प इस तरह बाँध कॉल करने से पहले:

int reuse = 1; 
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0) 
     perror("setsockopt(SO_REUSEADDR) failed"); 

#ifdef SO_REUSEPORT 
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0) 
     perror("setsockopt(SO_REUSEPORT) failed"); 
#endif 
संबंधित मुद्दे