so true

          心懷未來,開創未來!
          隨筆 - 160, 文章 - 0, 評論 - 40, 引用 - 0
          數據加載中……

          socket編程:SO_REUSEADDR例解

          轉載自:http://www.cppblog.com/ace/archive/2006/04/29/6446.html

          socket編程:SO_REUSEADDR例解

                                                      kevintz 2000-6-19

              網友vmstat多次提出了這個問題:SO_REUSEADDR有什么用處和怎么使用。而
          且很多網友在編寫網絡程序時也會遇到這個問題。所以特意寫了這么一篇文章,
          希望能夠解答一些人的疑難。
              其實這個問題在Richard Stevens的《Unix網絡編程指南》卷一里有很詳細的
          解答(中文版P166-168頁)。這里我只是寫幾個基本的例子來驗證這個問題。
              首先聲明一個問題:當兩個socket的address和port相沖突,而你又想重用地
          址和端口,則舊的socket和新的socket都要已經被設置了SO_REUSEADDR特性,只
          有兩者之一有這個特性還是有問題的。
              SO_REUSEADDR可以用在以下四種情況下。
              (摘自《Unix網絡編程》卷一,即UNPv1)
              1、當有一個有相同本地地址和端口的socket1處于TIME_WAIT狀態時,而你啟
          動的程序的socket2要占用該地址和端口,你的程序就要用到該選項。
              2、SO_REUSEADDR允許同一port上啟動同一服務器的多個實例(多個進程)。但
          每個實例綁定的IP地址是不能相同的。在有多塊網卡或用IP Alias技術的機器可
          以測試這種情況。
              3、SO_REUSEADDR允許單個進程綁定相同的端口到多個socket上,但每個soc
          ket綁定的ip地址不同。這和2很相似,區別請看UNPv1。
              4、SO_REUSEADDR允許完全相同的地址和端口的重復綁定。但這只用于UDP的
          多播,不用于TCP。

          例子1:測試上面第一種情況。
          #include <netinet/in.h> 
          #include 
          <sys/socket.h> 
          #include 
          <time.h> 
          #include 
          <stdio.h> 
          #include 
          <string.h> 

          #define MAXLINE 100 

          int main(int argc, char** argv) 

             
          int listenfd,connfd; 
             
          struct sockaddr_in servaddr; 
             
          char buff[MAXLINE+1]; 
             time_t ticks; 
             unsigned 
          short port; 
             
          int flag=1,len=sizeof(int); 

             port
          =10013
             
          if( (listenfd=socket(AF_INET,SOCK_STREAM,0)) == -1
             

               perror(
          "socket"); 
               exit(
          1); 
             }
           
             bzero(
          &servaddr,sizeof(servaddr)); 
             servaddr.sin_family
          =AF_INET; 
             servaddr.sin_addr.s_addr
          =htonl(INADDR_ANY); 
             servaddr.sin_port
          =htons(port); 
             
          if( setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &flag, len) == -
          1
             

                perror(
          "setsockopt"); 
                exit(
          1); 
             }
           
             
          if( bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) == 
          -1
             

                perror(
          "bind"); 
                exit(
          1); 
             }
           
             
          else 
                printf(
          "bind call OK!\n"); 
             
          if( listen(listenfd,5== -1
             

                perror(
          "listen"); 
                exit(
          1); 
             }
           
             
          for(;;) 
             

                
          if( (connfd=accept(listenfd,(struct sockaddr*)NULL,NULL)) == -1)

                

                    perror(
          "accept"); 
                    exit(
          1); 
                }
           
                
          if( fork() == 0)/*child process*/ 
                

                  close(listenfd);
          /*這句不能少,原因請大家想想就知道了。*/ 
                  ticks
          =time(NULL); 
                  snprintf(buff,
          100,"%.24s\r\n",ctime(&ticks)); 
                  write(connfd,buff,strlen(buff)); 
                  close(connfd); 
                  sleep(
          1); 
                  execlp(
          "f1-9d",NULL); 
                  perror(
          "execlp"); 
                  exit(
          1); 
               }
           
               close(connfd); 
               exit(
          0);/* end parent*/ 
            }
           
          }
           
          測試:編譯為f1-9d程序,放到一個自己PATH環境變量里的某個路徑里,例如$HO
          ME/bin,運行f1-9d,然后telnet localhost 10013看結果。

          2、第二種情況我沒有環境測,所以就不給測試程序了,大家有條件的可以自己寫
          一個來測試一下。
              
          3、測試第三種情況的程序
          #include <netinet/in.h> 
          #include 
          <sys/socket.h> 
          #include 
          <time.h> 
          #include 
          <stdio.h> 
          #include 
          <string.h> 

          #define MAXLINE 100 

          int main(int argc, char** argv) 

             
          int fd1,fd2; 
             
          struct sockaddr_in servaddr1,servaddr2; 
             
          char buff[MAXLINE+1]; 
             time_t ticks; 
             unsigned 
          short port; 
             
          int flag=1,len=sizeof(int); 

             port
          =10013
             
          if( (fd1=socket(AF_INET,SOCK_STREAM,0)) == -1
             

                 perror(
          "socket"); 
                 exit(
          1); 
             }
           
             
          if( (fd2=socket(AF_INET,SOCK_STREAM,0)) == -1
             

                 perror(
          "socket"); 
                 exit(
          1); 
             }
           
             bzero(
          &servaddr1,sizeof(servaddr1)); 
             bzero(
          &servaddr2,sizeof(servaddr2)); 
             servaddr1.sin_family
          =AF_INET; 
             servaddr2.sin_family
          =AF_INET; 

             
          if( inet_pton(AF_INET, "127.0.0.1"&servaddr1.sin_addr) <= 0

          printf(
          "inet_pton() call error:127.0.0.1\n"); 
          exit(
          1); 
          }
           
          if( inet_pton(AF_INET, "128.160.1.230"&servaddr2.sin_addr) <= 0


          printf(
          "inet_pton() call error:128.160.1.230\n"); 
          exit(
          1); 
          }
           
          servaddr1.sin_port
          =htons(port); 
          servaddr2.sin_port
          =htons(port); 
          if( setsockopt(fd1, SOL_SOCKET, SO_REUSEADDR, &flag, len) == -1

          perror(
          "setsockopt"); 
          exit(
          1); 
          }
           
          if( setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR, &flag, len) == -1

          perror(
          "setsockopt"); 
          exit(
          1); 
          }
           
          if( bind(fd1,(struct sockaddr*)&servaddr1,sizeof(servaddr1)) == -1)


          perror(
          "bind fd1"); 
          exit(
          1); 
          }
           
          if( bind(fd2,(struct sockaddr*)&servaddr2,sizeof(servaddr2)) == -1)


          perror(
          "bind fd2"); 
          exit(
          1); 
          }
           
          printf(
          "bind fd1 and fd2 OK!\n"); 
          /*put other process here*/ 
          getchar(); 
          exit(
          0);/* end */ 
          }
           

          4、由于第四種情況只用于UDP的多播,和TCP的使用沒多大關系,所以就不寫測試
          例子了。自己有興趣的可以寫。

          以上的程序都是在Linux下編譯通過的。也可以在其他unix平臺運行。

          參考資料:
          1、《Unix網絡編程》卷一 R. Stevens
          2、《Socket programming FAQ》 http://www.ibrado.com/sock-faq/

          posted on 2012-04-26 14:38 so true 閱讀(925) 評論(0)  編輯  收藏 所屬分類: C&C++

          主站蜘蛛池模板: 修武县| 乐陵市| 奉节县| 子长县| 汉中市| 耿马| 九寨沟县| 峨山| 靖边县| 海南省| 武陟县| 安图县| 宝鸡市| 台前县| 玉屏| 武平县| 丹寨县| 鹿泉市| 顺昌县| 绿春县| 灵寿县| 井冈山市| 甘孜县| 乃东县| 综艺| 乐亭县| 清河县| 柳林县| 东港市| 辽阳市| 哈尔滨市| 宜昌市| 舞阳县| 郑州市| 兴山县| 文水县| 禄丰县| 勃利县| 河北省| 绥阳县| 阳原县|