1. 程式人生 > >Connection refused問題的解決

Connection refused問題的解決

一、背景

系統:CentOS7 64位(執行在虛擬機器VMWare上)

虛擬網絡卡IP:192.168.137.129

使用的埠:9999

Sockets API處於堵塞模式(預設的)

二、問題描述

在終端1上,啟動伺服器後,可以成功監聽,即此時伺服器正等待客戶端的連線。但在終端2上,啟動客戶端後,返回一個錯誤——Connection refused(該資訊是通過strerror(errno)輸出的,strerror()在<string.h>中,errno在<errno.h>中)。

服務端部分程式碼。如下:

. . .

int sockfd;
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
   cout << strerror(errno) << endl;
   return -1;
}

struct sockaddr_in localaddr;
bzero(&localaddr, sizeof(localaddr));
localaddr.sin_family = AF_INET;
localaddr.sin_port = htonl(9999);
if (inet_pton(AF_INET, "192.168.137.129", &localaddr.sin_addr) <= 0)
{
   close(sockfd);
   cout << strerror(errno) << endl;
   return -1;
}

if (bind(sockfd, (struct sockaddr *)&localaddr, sizeof(localaddr)) < 0)
{
   close(sockfd);
   cout << strerror(errno) << endl;
   return -1;
}

if (listen(sockfd, 100) < 0)
{
   close(sockfd);
   cout << strerror(errno) << endl;
   return -1;
}

. . .


客戶端部分程式碼,如下:

. . .

int sockfd;
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
   cout << strerror(errno) << endl;
   return -1;
}

struct sockaddr_in srvaddr;
bzero(&srvaddr, sizeof(srvaddr));
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htonl(9999);
if (inet_pton(AF_INET, "192.168.137.129", &srvaddr.sin_addr) <= 0)
{
   close(sockfd);
   cout << strerror(errno) << endl;
   return -1;
}

if (connect(sockfd, (struct sockaddr *)&srvaddr, sizeof(srvaddr)) < 0)
{
   close(sockfd);
   cout << strerror(errno) << endl;
   return -1;
}

. . .
三、問題解決

將htonl(9999)替換成hons(9999),分別實施於伺服器與客戶端。

四、問題產生的原因

對於服務端:服務端原來的原始碼中,埠值設定為htonl(9999)。事實上,sockaddr_in.sin_port為短整型,佔16位;且CentOS7系統採用的位元組序為小端位元組序。因此,htonl(9999)的實際結果為0而非9999的網路位元組序。由於埠的實際值為0,這會導致當服務端呼叫函式listen時,核心會為服務端選擇一個臨時埠,這個臨時埠通常與我們所指定的埠並不相同。

對於客戶端:事實上,客戶端所請求的埠號為0(保留埠)。當客戶端在呼叫函式connect時,伺服器端在客戶端所請求的埠上沒有服務在等待連線,所以connect最終出錯返回,出錯的原因正如我們所看到的:Connection refused。

五、總結

引起Connection refused的可能原因:服務端在客戶端所請求的埠上沒有服務在等待連線。

也許是服務端根本沒有啟動;也許是服務端啟動成功了,但客戶端所請求的埠與服務端正在監聽的埠不一致(客戶端所請求的埠並不一定與我們所指定的一致,服務端正在監聽的埠也並不一定與我們所指定的一致,這正是本文所討論的內容)。當然,不排除還存在其他情況會導致此錯誤,只是筆者還未遇到或聽說而已。