本文將會闡述兩種解決端口占用的方法。
本文會用到的服務器端的程序如下:
1 #include "unp.h" 2 #include <time.h> 3 4 int main(int argc, char **argv) 5 { 6 int listenfd, connfd; 7 socklen_t len; 8 struct sockaddr_in servaddr, cliaddr; 9 char buff[MAXLINE]; 10 time_t ticks; 11 12 listenfd = Socket(AF_INET, SOCK_STREAM, 0); 13 14 bzero(&servaddr, sizeof(servaddr)); 15 servaddr.sin_family = AF_INET; 16 servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 17 servaddr.sin_port = htons(13); /* daytime server */ 18 19 int on = 1; 20 Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 21 22 Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); 23 24 Listen(listenfd, LISTENQ); 25 26 for(; ;) 27 { 28 len = sizeof(cliaddr); 29 connfd = Accept(listenfd, (SA *)&cliaddr, &len); 30 31 printf("connection from %s, port %d\n", 32 Inet_ntop(AF_INET, &cliaddr.sin_addr, buff, sizeof(buff)), 33 ntohs(cliaddr.sin_port)); 34 35 ticks = time(NULL); 36 snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks)); 37 Write(connfd, buff, strlen(buff)); 38 39 Close(connfd); 40 } 41 42 exit(0); 43 }
該程序試圖將TCP套接字綁定到13號端口(“給請求主機發送日期和時間”)。
問題描述
如果一個端口已經被占用,而我們的程序又綁定到該端口,則我們在運行程序的時候系統會提示錯誤:“bind error: Address already in use”,即端口已被占用。
解決方法1:關閉使用該端口的進程
這種方法應該是最笨的了,而且在實際中我們不大可能這樣子做。
我們運行了上邊提到的程序,得到了下邊的結果:

很明顯,已經有進程占用了這個端口。我們可以先看一下是哪些服務占用了端口(在這里是13):

從上圖可以看出是TCP服務占用了這個端口。我們接下來看一下是什么進程開啟了這個TCP服務:

現在我們知道是xinetd服務占用了這個接口。我們直接關閉掉這個服務:
![]()
現在開啟我們的服務端程序就沒問題了。
解決方法2:設置端口為可重用
在IBM的一篇文章Linux 套接字編程中的 5 個隱患中作者提出用函數setsockopt來設定端口可重用,代碼如下:
/* Enable address reuse */ on = 1; ret = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );
但在我們的程序中,用了這種方法還是不行()。
出現這個問題的原因在於開啟我們自己的程序前我們已經開啟了其它占用13號端口的服務(如xinetd),而該已占用13號端口的服務卻沒有設定13號端口為可重用,最終導致我們的程序綁定端口錯誤。
正確的做法是第一個使用13號(對其它端口號也一樣)端口的進程要設定13號端口為可重用,這樣后續使用該端口的進程方能綁定成功。
所以我們要先運行我們的程序,將13號端口設定為可重用,然后再運行其它使用該端口的進程(如xinetd)。用這種方法,我們的程序和xinetd服務終於能夠同時綁定端口號13,如下圖所示:

