自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux網(wǎng)絡(luò)編程之綁定端口注意事項(xiàng)及端口復(fù)用

網(wǎng)絡(luò) 通信技術(shù)
所謂綁定(bind)是指別人連接我只能通過(guò)我所綁定的端口,相當(dāng)于,我買(mǎi)了一個(gè)手機(jī),別人要想聯(lián)系我,必須要知道我的手機(jī)號(hào)碼,這時(shí)候,我需要怎么辦呢?我需要給手機(jī)插上電話(huà)卡,固定一個(gè)電話(huà)號(hào)碼,這樣別人就能通過(guò)這個(gè)電話(huà)號(hào)碼聯(lián)系我。手機(jī)插上電話(huà)卡,固定一個(gè)電話(huà)號(hào)碼,類(lèi)似于綁定(bind)的過(guò)程。

所謂綁定(bind)是指別人連接我只能通過(guò)我所綁定的端口,相當(dāng)于,我買(mǎi)了一個(gè)手機(jī),別人要想聯(lián)系我,必須要知道我的手機(jī)號(hào)碼,這時(shí)候,我需要怎么辦呢?我需要給手機(jī)插上電話(huà)卡,固定一個(gè)電話(huà)號(hào)碼,這樣別人就能通過(guò)這個(gè)電話(huà)號(hào)碼聯(lián)系我。手機(jī)插上電話(huà)卡,固定一個(gè)電話(huà)號(hào)碼,類(lèi)似于綁定(bind)的過(guò)程,綁定(bind)為了固定一個(gè)端口號(hào),別的網(wǎng)絡(luò)程序就可以找到這個(gè)端口號(hào),找到這個(gè)端口號(hào)就能找到這個(gè)端口號(hào)所對(duì)應(yīng)的網(wǎng)絡(luò)應(yīng)用程序。

在網(wǎng)絡(luò)編程里,通常都是在服務(wù)器里綁定(bind)端口,這并不是說(shuō)客戶(hù)端里不能綁定(bind)端口,但這里需要注意的是,一個(gè)網(wǎng)絡(luò)應(yīng)用程序只能綁定一個(gè)端口( 一個(gè)套接字只能 綁定一個(gè)端口 )。

一個(gè)套接字不能同時(shí)綁定多個(gè)端口,如下:

  1. #include <stdio.h>    
  2. #include <stdlib.h>    
  3. #include <string.h>    
  4. #include <unistd.h>    
  5. #include <sys/socket.h>    
  6. #include <netinet/in.h>    
  7. #include <arpa/inet.h>    
  8.     
  9. int main(int argc, charchar *argv[])    
  10. {    
  11.     char server_ip[30] = "10.221.20.12";    
  12.     
  13.     int sockfd;    
  14.     sockfd = socket(AF_INET, SOCK_DGRAM, 0);        //創(chuàng)建UDP套接字    
  15.     if(sockfd < 0)    
  16.     {    
  17.         perror("socket");    
  18.         exit(-1);    
  19.     }    
  20.     
  21.     // 初始化本地網(wǎng)絡(luò)信息    
  22.     struct sockaddr_in my_addr;    
  23.     bzero(&my_addr, sizeof(my_addr));    
  24.     my_addr.sin_family = AF_INET;    
  25.     my_addr.sin_port   = htons(8000);    
  26.     my_addr.sin_addr.s_addr = htonl(INADDR_ANY);    
  27.     
  28.     // ***次綁定端口8000    
  29.     int err_log;    
  30.     err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));    
  31.     if(err_log != 0)    
  32.     {    
  33.         perror("bind 8000");    
  34.         close(sockfd);          
  35.         exit(-1);    
  36.     }    
  37.     
  38.     // 又一次綁定別的端口9000, 會(huì)綁定失敗    
  39.     my_addr.sin_port = htons(9000);    
  40.     err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));    
  41.     if(err_log != 0)    
  42.     {    
  43.         perror("bind 9000");    
  44.         close(sockfd);          
  45.         exit(-1);    
  46.     }    
  47.     
  48.     close(sockfd);    
  49.     return 0;    
  50. }   

程序編譯運(yùn)行后結(jié)果如下: 

[[133623]] 

如果客戶(hù)端想綁定端口號(hào),一定要調(diào)用發(fā)送信息函數(shù)之前綁定( bind )端口,因?yàn)樵诎l(fā)送信息函數(shù)( sendto, 或 write ),系統(tǒng)會(huì)自動(dòng)給當(dāng)前網(wǎng)絡(luò)程序分配一個(gè)隨機(jī)端口號(hào),這相當(dāng)于隨機(jī)綁定了一個(gè)端口號(hào),這里只會(huì)分配一次,以后通信就以這個(gè)隨機(jī)端口通信,我們?cè)俳壎ǘ丝谔?hào)的話(huà),就會(huì)綁定失敗。如果我們放在發(fā)送信息函數(shù)( sendto, 或 write )之前綁定,那樣程序?qū)⒁晕覀兘壎ǖ亩丝谔?hào)發(fā)送信息,不會(huì)再隨機(jī)分配一個(gè)端口號(hào)。

綁定失敗例子( UDP )如下:

  1. #include <stdio.h>    
  2. #include <stdlib.h>    
  3. #include <string.h>    
  4. #include <unistd.h>    
  5. #include <sys/socket.h>    
  6. #include <netinet/in.h>    
  7. #include <arpa/inet.h>    
  8.     
  9. int main(int argc, charchar *argv[])    
  10. {    
  11.     char server_ip[30] = "10.221.20.12";    
  12.         
  13.     int sockfd;    
  14.     sockfd = socket(AF_INET, SOCK_DGRAM, 0);        //創(chuàng)建UDP套接字    
  15.     if(sockfd < 0)    
  16.     {    
  17.         perror("socket");    
  18.         exit(-1);    
  19.     }    
  20.         
  21.     struct sockaddr_in dest_addr;    
  22.     bzero(&dest_addr, sizeof(dest_addr));    
  23.     dest_addr.sin_family = AF_INET;    
  24.     dest_addr.sin_port   = htons(8080); // 服務(wù)器的端口    
  25.     inet_pton(AF_INET, server_ip, &dest_addr.sin_addr);    
  26.         
  27.     char send_buf[512] = "this is for test";    
  28.     // 如果前面沒(méi)有綁定端口,sendto()系統(tǒng)會(huì)隨機(jī)分配一個(gè)端口    
  29.     sendto(sockfd, send_buf, strlen(send_buf), 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr));//發(fā)送數(shù)據(jù)    
  30.         
  31.     // 初始化本地網(wǎng)絡(luò)信息    
  32.     struct sockaddr_in my_addr;    
  33.     bzero(&my_addr, sizeof(my_addr));    
  34.     my_addr.sin_family = AF_INET;    
  35.     my_addr.sin_port   = htons(8000);    
  36.     my_addr.sin_addr.s_addr = htonl(INADDR_ANY);    
  37.         
  38.     // sendto()后面綁定端口,綁定失敗    
  39.     int err_log;    
  40.     err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));    
  41.     if(err_log != 0)    
  42.     {    
  43.         perror("bind 8000");    
  44.         close(sockfd);          
  45.         exit(-1);    
  46.     }    
  47.     
  48.     close(sockfd);    
  49.     return 0;    
  50. }   

程序編譯運(yùn)行后結(jié)果如下: 

[[133624]] #p#

在上面提到:一個(gè)網(wǎng)絡(luò)應(yīng)用程序只能綁定一個(gè)端口( 一個(gè)套接字只能綁定一個(gè)端口 )。

實(shí)際上,默認(rèn)的情況下,如果一個(gè)網(wǎng)絡(luò)應(yīng)用程序的一個(gè)套接字 綁定了一個(gè)端口( 占用了 8000 ),這時(shí)候,別的套接字就無(wú)法使用這個(gè)端口( 8000 ), 驗(yàn)證例子如下:

  1. #include <stdio.h>    
  2. #include <stdlib.h>    
  3. #include <string.h>    
  4. #include <unistd.h>    
  5. #include <sys/socket.h>    
  6. #include <netinet/in.h>    
  7. #include <arpa/inet.h>    
  8.     
  9. int main(int argc, charchar *argv[])    
  10. {    
  11.     int sockfd_one;    
  12.     int err_log;    
  13.     sockfd_one = socket(AF_INET, SOCK_DGRAM, 0); //創(chuàng)建UDP套接字one    
  14.     if(sockfd_one < 0)    
  15.     {    
  16.     perror("sockfd_one");    
  17.     exit(-1);    
  18.     }    
  19.     
  20.     // 設(shè)置本地網(wǎng)絡(luò)信息    
  21.     struct sockaddr_in my_addr;    
  22.     bzero(&my_addr, sizeof(my_addr));    
  23.     my_addr.sin_family = AF_INET;    
  24.     my_addr.sin_port = htons(8000);     // 端口為8000    
  25.     my_addr.sin_addr.s_addr = htonl(INADDR_ANY);    
  26.     
  27.     // 綁定,端口為8000    
  28.     err_log = bind(sockfd_one, (struct sockaddr*)&my_addr, sizeof(my_addr));    
  29.     if(err_log != 0)    
  30.     {    
  31.         perror("bind sockfd_one");    
  32.         close(sockfd_one);          
  33.         exit(-1);    
  34.     }    
  35.     
  36.     int sockfd_two;    
  37.     sockfd_two = socket(AF_INET, SOCK_DGRAM, 0);  //創(chuàng)建UDP套接字two    
  38.     if(sockfd_two < 0)    
  39.     {    
  40.         perror("sockfd_two");    
  41.         exit(-1);    
  42.     }    
  43.     
  44.     // 新套接字sockfd_two,繼續(xù)綁定8000端口,綁定失敗    
  45.     // 因?yàn)?000端口已被占用,默認(rèn)情況下,端口沒(méi)有釋放,無(wú)法綁定    
  46.     err_log = bind(sockfd_two, (struct sockaddr*)&my_addr, sizeof(my_addr));    
  47.     if(err_log != 0)    
  48.     {    
  49.         perror("bind sockfd_two");    
  50.         close(sockfd_two);          
  51.         exit(-1);    
  52.     }    
  53.     
  54.     close(sockfd_one);    
  55.     close(sockfd_two);    
  56.     
  57.     return 0;    
  58. }   

程序編譯運(yùn)行后結(jié)果如下: 

[[133625]] 

那如何讓sockfd_one, sockfd_two兩個(gè)套接字都能成功綁定8000端口呢?這時(shí)候就需要要到端口復(fù)用了。端口復(fù)用允許在一個(gè)應(yīng)用程序可以把 n 個(gè)套接字綁在一個(gè)端口上而不出錯(cuò)。

設(shè)置socket的SO_REUSEADDR選項(xiàng),即可實(shí)現(xiàn)端口復(fù)用:

  1. int opt = 1;    
  2. // sockfd為需要端口復(fù)用的套接字    
  3. setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const voidvoid *)&opt, sizeof(opt));   

SO_REUSEADDR可以用在以下四種情況下。 (摘自《Unix網(wǎng)絡(luò)編程》卷一,即UNPv1)

1、當(dāng)有一個(gè)有相同本地地址和端口的socket1處于TIME_WAIT狀態(tài)時(shí),而你啟動(dòng)的程序的socket2要占用該地址和端口,你的程序就要用到該選項(xiàng)。

2、SO_REUSEADDR允許同一port上啟動(dòng)同一服務(wù)器的多個(gè)實(shí)例(多個(gè)進(jìn)程)。但每個(gè)實(shí)例綁定的IP地址是不能相同的。在有多塊網(wǎng)卡或用IP Alias技術(shù)的機(jī)器可以測(cè)試這種情況。

3、SO_REUSEADDR允許單個(gè)進(jìn)程綁定相同的端口到多個(gè)socket上,但每個(gè)socket綁定的ip地址不同。這和2很相似,區(qū)別請(qǐng)看UNPv1。

4、SO_REUSEADDR允許完全相同的地址和端口的重復(fù)綁定。但這只用于UDP的多播,不用于TCP。

需要注意的是,設(shè)置端口復(fù)用函數(shù)要在綁定之前調(diào)用,而且只要綁定到同一個(gè)端口的所有套接字都得設(shè)置復(fù)用:

  1. // sockfd_one, sockfd_two都要設(shè)置端口復(fù)用    
  2. // 在sockfd_one綁定bind之前,設(shè)置其端口復(fù)用    
  3. int opt = 1;    
  4. setsockopt( sockfd_one, SOL_SOCKET,SO_REUSEADDR, (const voidvoid *)&opt, sizeof(opt) );    
  5. err_log = bind(sockfd_one, (struct sockaddr*)&my_addr, sizeof(my_addr));    
  6.     
  7. // 在sockfd_two綁定bind之前,設(shè)置其端口復(fù)用    
  8. opt = 1;    
  9. setsockopt( sockfd_two, SOL_SOCKET,SO_REUSEADDR,(const voidvoid *)&opt, sizeof(opt) );    
  10. err_log = bind(sockfd_two, (struct sockaddr*)&my_addr, sizeof(my_addr));   

端口復(fù)用完整代碼如下:

  1. #include <stdio.h>    
  2. #include <stdlib.h>    
  3. #include <string.h>    
  4. #include <unistd.h>    
  5. #include <sys/socket.h>    
  6. #include <netinet/in.h>    
  7. #include <arpa/inet.h>    
  8.     
  9. int main(int argc, charchar *argv[])    
  10. {    
  11.     int sockfd_one;    
  12.     int err_log;    
  13.     sockfd_one = socket(AF_INET, SOCK_DGRAM, 0); //創(chuàng)建UDP套接字one    
  14.     if(sockfd_one < 0)    
  15.     {    
  16.     perror("sockfd_one");    
  17.     exit(-1);    
  18.     }    
  19.     
  20.     // 設(shè)置本地網(wǎng)絡(luò)信息    
  21.     struct sockaddr_in my_addr;    
  22.     bzero(&my_addr, sizeof(my_addr));    
  23.     my_addr.sin_family = AF_INET;    
  24.     my_addr.sin_port = htons(8000);     // 端口為8000    
  25.     my_addr.sin_addr.s_addr = htonl(INADDR_ANY);    
  26.         
  27.     // 在sockfd_one綁定bind之前,設(shè)置其端口復(fù)用    
  28.     int opt = 1;    
  29.     setsockopt( sockfd_one, SOL_SOCKET,SO_REUSEADDR,     
  30.                     (const voidvoid *)&opt, sizeof(opt) );    
  31.     
  32.     // 綁定,端口為8000    
  33.     err_log = bind(sockfd_one, (struct sockaddr*)&my_addr, sizeof(my_addr));    
  34.     if(err_log != 0)    
  35.     {    
  36.         perror("bind sockfd_one");    
  37.         close(sockfd_one);          
  38.         exit(-1);    
  39.     }    
  40.     
  41.     int sockfd_two;    
  42.     sockfd_two = socket(AF_INET, SOCK_DGRAM, 0);  //創(chuàng)建UDP套接字two    
  43.     if(sockfd_two < 0)    
  44.     {    
  45.         perror("sockfd_two");    
  46.         exit(-1);    
  47.     }    
  48.     
  49.     // 在sockfd_two綁定bind之前,設(shè)置其端口復(fù)用    
  50.     opt = 1;    
  51.     setsockopt( sockfd_two, SOL_SOCKET,SO_REUSEADDR,     
  52.                     (const voidvoid *)&opt, sizeof(opt) );    
  53.         
  54.     // 新套接字sockfd_two,繼續(xù)綁定8000端口,成功    
  55.     err_log = bind(sockfd_two, (struct sockaddr*)&my_addr, sizeof(my_addr));    
  56.     if(err_log != 0)    
  57.     {    
  58.         perror("bind sockfd_two");    
  59.         close(sockfd_two);          
  60.         exit(-1);    
  61.     }    
  62.     
  63.     close(sockfd_one);    
  64.     close(sockfd_two);    
  65.     
  66.     return 0;    
  67. }    

端口復(fù)用允許在一個(gè)應(yīng)用程序可以把 n 個(gè)套接字綁在一個(gè)端口上而不出錯(cuò)。同時(shí),這 n 個(gè)套接字發(fā)送信息都正常,沒(méi)有問(wèn)題。但是,這些套接字并不是所有都能讀取信息,只有***一個(gè)套接字會(huì)正常接收數(shù)據(jù)。

下面,我們?cè)谥暗拇a上,添加兩個(gè)線(xiàn)程,分別負(fù)責(zé)接收sockfd_one,sockfd_two的信息:

  1. #include <stdio.h>    
  2. #include <stdlib.h>    
  3. #include <string.h>    
  4. #include <unistd.h>    
  5. #include <sys/socket.h>    
  6. #include <netinet/in.h>    
  7. #include <arpa/inet.h>    
  8. #include <pthread.h>    
  9.     
  10. // 線(xiàn)程1的回調(diào)函數(shù)    
  11. voidvoid *recv_one(voidvoid *arg)    
  12. {    
  13.     printf("===========recv_one==============\n");    
  14.     int sockfd = (int )arg;    
  15.     while(1){    
  16.         int recv_len;    
  17.         char recv_buf[512] = "";    
  18.         struct sockaddr_in client_addr;    
  19.         char cli_ip[INET_ADDRSTRLEN] = "";//INET_ADDRSTRLEN=16    
  20.         socklen_t cliaddr_len = sizeof(client_addr);    
  21.             
  22.         recv_len = recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr*)&client_addr, &cliaddr_len);    
  23.         inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);    
  24.         printf("\nip:%s ,port:%d\n",cli_ip, ntohs(client_addr.sin_port));    
  25.         printf("sockfd_one =========== data(%d):%s\n",recv_len,recv_buf);    
  26.         
  27.     }    
  28.     
  29.     return NULL;    
  30. }    
  31.     
  32. // 線(xiàn)程2的回調(diào)函數(shù)    
  33. voidvoid *recv_two(voidvoid *arg)    
  34. {    
  35.     printf("+++++++++recv_two++++++++++++++\n");    
  36.     int sockfd = (int )arg;    
  37.     while(1){    
  38.         int recv_len;    
  39.         char recv_buf[512] = "";    
  40.         struct sockaddr_in client_addr;    
  41.         char cli_ip[INET_ADDRSTRLEN] = "";//INET_ADDRSTRLEN=16    
  42.         socklen_t cliaddr_len = sizeof(client_addr);    
  43.             
  44.         recv_len = recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr*)&client_addr, &cliaddr_len);    
  45.         inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);    
  46.         printf("\nip:%s ,port:%d\n",cli_ip, ntohs(client_addr.sin_port));    
  47.         printf("sockfd_two @@@@@@@@@@@@@@@ data(%d):%s\n",recv_len,recv_buf);    
  48.         
  49.     }    
  50.     
  51.     return NULL;    
  52. }    
  53.     
  54. int main(int argc, charchar *argv[])    
  55. {    
  56.     int err_log;    
  57.         
  58.     /////////////////////////sockfd_one    
  59.     int sockfd_one;    
  60.     sockfd_one = socket(AF_INET, SOCK_DGRAM, 0); //創(chuàng)建UDP套接字one    
  61.     if(sockfd_one < 0)    
  62.     {    
  63.     perror("sockfd_one");    
  64.     exit(-1);    
  65.     }    
  66.     
  67.     // 設(shè)置本地網(wǎng)絡(luò)信息    
  68.     struct sockaddr_in my_addr;    
  69.     bzero(&my_addr, sizeof(my_addr));    
  70.     my_addr.sin_family = AF_INET;    
  71.     my_addr.sin_port = htons(8000);     // 端口為8000    
  72.     my_addr.sin_addr.s_addr = htonl(INADDR_ANY);    
  73.         
  74.     // 在sockfd_one綁定bind之前,設(shè)置其端口復(fù)用    
  75.     int opt = 1;    
  76.     setsockopt( sockfd_one, SOL_SOCKET,SO_REUSEADDR,     
  77.                     (const voidvoid *)&opt, sizeof(opt) );    
  78.     
  79.     // 綁定,端口為8000    
  80.     err_log = bind(sockfd_one, (struct sockaddr*)&my_addr, sizeof(my_addr));    
  81.     if(err_log != 0)    
  82.     {    
  83.         perror("bind sockfd_one");    
  84.         close(sockfd_one);          
  85.         exit(-1);    
  86.     }    
  87.         
  88.     //接收信息線(xiàn)程1    
  89.     pthread_t tid_one;    
  90.     pthread_create(&tid_one, NULL, recv_one, (voidvoid *)sockfd_one);    
  91.         
  92.     /////////////////////////sockfd_two    
  93.     int sockfd_two;    
  94.     sockfd_two = socket(AF_INET, SOCK_DGRAM, 0);  //創(chuàng)建UDP套接字two    
  95.     if(sockfd_two < 0)    
  96.     {    
  97.         perror("sockfd_two");    
  98.         exit(-1);    
  99.     }    
  100.     
  101.     // 在sockfd_two綁定bind之前,設(shè)置其端口復(fù)用    
  102.     opt = 1;    
  103.     setsockopt( sockfd_two, SOL_SOCKET,SO_REUSEADDR,     
  104.                     (const voidvoid *)&opt, sizeof(opt) );    
  105.         
  106.     // 新套接字sockfd_two,繼續(xù)綁定8000端口,成功    
  107.     err_log = bind(sockfd_two, (struct sockaddr*)&my_addr, sizeof(my_addr));    
  108.     if(err_log != 0)    
  109.     {    
  110.         perror("bind sockfd_two");    
  111.         close(sockfd_two);          
  112.         exit(-1);    
  113.     }    
  114.     //接收信息線(xiàn)程2    
  115.     pthread_t tid_two;    
  116.     pthread_create(&tid_two, NULL, recv_two, (voidvoid *)sockfd_two);    
  117.         
  118.         
  119.     while(1){   // 讓程序阻塞在這,不結(jié)束    
  120.         NULL;    
  121.     }    
  122.     
  123.     close(sockfd_one);    
  124.     close(sockfd_two);    
  125.     
  126.     return 0;    
  127. }   

接著,通過(guò)網(wǎng)絡(luò)調(diào)試助手給這個(gè)服務(wù)器發(fā)送數(shù)據(jù),結(jié)果顯示,只有***一個(gè)套接字sockfd_two會(huì)正常接收數(shù)據(jù): 

[[133626]] 

我們上面的用法,實(shí)際上沒(méi)有太大的意義。端口復(fù)用最常用的用途應(yīng)該是防止服務(wù)器重啟時(shí)之前綁定的端口還未釋放或者程序突然退出而系統(tǒng)沒(méi)有釋放端口。這種情況下如果設(shè)定了端口復(fù)用,則新啟動(dòng)的服務(wù)器進(jìn)程可以直接綁定端口。如果沒(méi)有設(shè)定端口復(fù)用,綁定會(huì)失敗,提示ADDR已經(jīng)在使用中——那只好等等再重試了,麻煩!

責(zé)任編輯:藍(lán)雨淚 來(lái)源: CSDN博客
相關(guān)推薦

2015-05-04 14:51:49

SQL子查詢(xún)

2009-09-01 17:25:33

初學(xué)C#編程

2009-11-09 11:01:01

ibmdwPMP

2011-06-23 11:15:25

SEO網(wǎng)站優(yōu)化

2011-04-14 11:28:07

光纖

2014-07-29 10:12:38

LinuxC語(yǔ)言編程

2011-07-22 13:25:10

復(fù)印機(jī)租賃技巧

2009-07-15 16:14:36

iBATIS優(yōu)缺點(diǎn)

2010-01-21 11:30:10

2009-09-07 08:58:23

VMWare編譯lin

2014-01-13 10:50:28

虛擬化存儲(chǔ)

2010-01-08 10:28:22

交換網(wǎng)絡(luò)技術(shù)

2011-05-26 11:22:04

SEO

2009-12-15 17:47:17

VSIP

2011-05-19 14:29:50

Oracle存儲(chǔ)語(yǔ)法

2021-12-14 14:50:12

synchronizeJava

2021-02-07 07:40:31

Synchronize用法

2009-06-14 08:40:14

Linux平臺(tái)公司

2009-12-03 14:37:47

安裝phpMyAdmi

2009-06-12 09:46:40

Java String
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)