程序源碼:
DWORD WINAPI CServerSocket:: ListenThread(LPVOID lparam)
{
try
{
//加以下語句可消除Debug時(shí)出現(xiàn)的afxwin1.inl的報(bào)錯(cuò)
//該錯(cuò)誤在Release時(shí)是不出現(xiàn)的
//AFX_MANAGE_STATE(AfxGetStaticModuleState());
CServerSocket *pServerSocket=(CServerSocket *)lparam;
int createSucceed=pServerSocket->Create(pServerSocket->intPort); //第2次執(zhí)行時(shí)在這里出現(xiàn)WSAEADDRINUSE錯(cuò)誤,原因是端口被占用
if(createSucceed==0)
{
AfxMessageBox("_ListenTcpThread Create錯(cuò)誤!"+pServerSocket->GetError(GetLastError()));
return -1;
}
int listenSucceed=pServerSocket->Listen(10); //開始監(jiān)聽
if(listenSucceed==0)
{
AfxMessageBox("_ListenTcpThread Listen錯(cuò)誤!"+pServerSocket->GetError(GetLastError()));
return -1;
}
CSocket recSo;
SOCKADDR_IN client;
int iAddrSize=sizeof(client);
int intSucceed=pServerSocket->Accept(recSo,(SOCKADDR *)&client,&iAddrSize); //接受連接并取得對(duì)方IP
....
}
先是查了不少文章,一堆搞不明白狀況的家伙胡亂指點(diǎn),有的說是要AfxSocketInit(),有的說換個(gè)端口就可以了!
問題是我的這個(gè)端口是監(jiān)聽的,我隨機(jī)換的話,遠(yuǎn)程的Client哪里知道該找哪個(gè)來連接???
總算找到下面的一段文字,把原理給說清楚了!解決辦法也很清楚 !
我的處理是,退出線程之前做一下SetSockOpt,代碼如下:
//停止服務(wù)程序監(jiān)聽
BOOL CServerSocket::StopServer()
{
DWORD exitcode;
WaitForSingleObject(m_hServerThread,500);
//解決WSAEADDRINUSE錯(cuò)誤的解決辦法 start
//加這幾句可以解決:停止監(jiān)聽,再重新開啟監(jiān)聽出現(xiàn)Create語句發(fā)生WSAEADDRINUSE錯(cuò)誤的問題
//問題提示端口已經(jīng)被占用
BOOL bDontLinger=FALSE;
this->SetSockOpt(SO_DONTLINGER,(const char *)&bDontLinger,sizeof(bDontLinger),SOL_SOCKET);
this->Close();
//解決WSAEADDRINUSE錯(cuò)誤的解決辦法 end
if(!GetExitCodeThread(m_hServerThread,&exitcode))
{
TerminateThread(m_hServerThread,exitcode);
}
m_hServerThread=NULL;
return 0;
}
為什么TCP關(guān)閉后端口會(huì)處于TIME_WAIT狀態(tài)?
一般來說,tcp正常關(guān)閉需要四個(gè)包。比如a和b關(guān)閉連接,a先給b發(fā)一個(gè)fin,b會(huì)進(jìn)行確認(rèn)ack,然后b也會(huì)發(fā)出fin,當(dāng)a接受到這個(gè)fin,并發(fā)出最后一個(gè)ack后,就會(huì)處于time_wait狀態(tài)。這個(gè)時(shí)間長(zhǎng)短跟操作系統(tǒng)有關(guān),一般會(huì)在1-4分鐘,也就是兩倍的數(shù)據(jù)包(2msl)生存時(shí)間。TCP主動(dòng)關(guān)閉方采用TIME_WAIT主要是為了實(shí)現(xiàn)終止TCP全雙工連接的可靠性及允許老的重復(fù)分節(jié)在網(wǎng)絡(luò)中消逝,等過了2msl(大約1~4分鐘)后TIME_WAIT就會(huì)消失。
所以說,主動(dòng)發(fā)起關(guān)閉連接的一方會(huì)進(jìn)入time_wait狀態(tài),這個(gè)時(shí)候,進(jìn)程所占用的端口號(hào)不能被釋放。除非在你的程序中用setsockopt設(shè)置端口可重用(SOCK_REUSE)的選項(xiàng),但這不是所有操作系統(tǒng)都支持的,解決TIME_WAIT的辦法我個(gè)人認(rèn)為以下兩種比較好:
禁用LINGER
//Socket API
BOOL bDontLinger=FALSE;
setsockopt(m_socket,SOL_SOCKET,SO_DONTLINGER,(LPCTSTR)&bDontLinger,sizeof(BOOL));
closesocket(s);
//MFC CAsyncSocket或者CSocket
BOOL bDontLinger=FALSE;
m_socket->SetSockOpt(SO_DONTLINGER,(const char *)&bDontLinger,sizeof(bDontLinger),SOL_SOCKET);
m_socket->Close();
DWORD WINAPI CServerSocket:: ListenThread(LPVOID lparam)
{
try
{
//加以下語句可消除Debug時(shí)出現(xiàn)的afxwin1.inl的報(bào)錯(cuò)
//該錯(cuò)誤在Release時(shí)是不出現(xiàn)的
//AFX_MANAGE_STATE(AfxGetStaticModuleState());
CServerSocket *pServerSocket=(CServerSocket *)lparam;
int createSucceed=pServerSocket->Create(pServerSocket->intPort); //第2次執(zhí)行時(shí)在這里出現(xiàn)WSAEADDRINUSE錯(cuò)誤,原因是端口被占用
if(createSucceed==0)
{
AfxMessageBox("_ListenTcpThread Create錯(cuò)誤!"+pServerSocket->GetError(GetLastError()));
return -1;
}
int listenSucceed=pServerSocket->Listen(10); //開始監(jiān)聽
if(listenSucceed==0)
{
AfxMessageBox("_ListenTcpThread Listen錯(cuò)誤!"+pServerSocket->GetError(GetLastError()));
return -1;
}
CSocket recSo;
SOCKADDR_IN client;
int iAddrSize=sizeof(client);
int intSucceed=pServerSocket->Accept(recSo,(SOCKADDR *)&client,&iAddrSize); //接受連接并取得對(duì)方IP
....
}
先是查了不少文章,一堆搞不明白狀況的家伙胡亂指點(diǎn),有的說是要AfxSocketInit(),有的說換個(gè)端口就可以了!
問題是我的這個(gè)端口是監(jiān)聽的,我隨機(jī)換的話,遠(yuǎn)程的Client哪里知道該找哪個(gè)來連接???
總算找到下面的一段文字,把原理給說清楚了!解決辦法也很清楚 !
我的處理是,退出線程之前做一下SetSockOpt,代碼如下:
//停止服務(wù)程序監(jiān)聽
BOOL CServerSocket::StopServer()
{
DWORD exitcode;
WaitForSingleObject(m_hServerThread,500);
//解決WSAEADDRINUSE錯(cuò)誤的解決辦法 start
//加這幾句可以解決:停止監(jiān)聽,再重新開啟監(jiān)聽出現(xiàn)Create語句發(fā)生WSAEADDRINUSE錯(cuò)誤的問題
//問題提示端口已經(jīng)被占用
BOOL bDontLinger=FALSE;
this->SetSockOpt(SO_DONTLINGER,(const char *)&bDontLinger,sizeof(bDontLinger),SOL_SOCKET);
this->Close();
//解決WSAEADDRINUSE錯(cuò)誤的解決辦法 end
if(!GetExitCodeThread(m_hServerThread,&exitcode))
{
TerminateThread(m_hServerThread,exitcode);
}
m_hServerThread=NULL;
return 0;
}
為什么TCP關(guān)閉后端口會(huì)處于TIME_WAIT狀態(tài)?
一般來說,tcp正常關(guān)閉需要四個(gè)包。比如a和b關(guān)閉連接,a先給b發(fā)一個(gè)fin,b會(huì)進(jìn)行確認(rèn)ack,然后b也會(huì)發(fā)出fin,當(dāng)a接受到這個(gè)fin,并發(fā)出最后一個(gè)ack后,就會(huì)處于time_wait狀態(tài)。這個(gè)時(shí)間長(zhǎng)短跟操作系統(tǒng)有關(guān),一般會(huì)在1-4分鐘,也就是兩倍的數(shù)據(jù)包(2msl)生存時(shí)間。TCP主動(dòng)關(guān)閉方采用TIME_WAIT主要是為了實(shí)現(xiàn)終止TCP全雙工連接的可靠性及允許老的重復(fù)分節(jié)在網(wǎng)絡(luò)中消逝,等過了2msl(大約1~4分鐘)后TIME_WAIT就會(huì)消失。
所以說,主動(dòng)發(fā)起關(guān)閉連接的一方會(huì)進(jìn)入time_wait狀態(tài),這個(gè)時(shí)候,進(jìn)程所占用的端口號(hào)不能被釋放。除非在你的程序中用setsockopt設(shè)置端口可重用(SOCK_REUSE)的選項(xiàng),但這不是所有操作系統(tǒng)都支持的,解決TIME_WAIT的辦法我個(gè)人認(rèn)為以下兩種比較好:
禁用LINGER
//Socket API
BOOL bDontLinger=FALSE;
setsockopt(m_socket,SOL_SOCKET,SO_DONTLINGER,(LPCTSTR)&bDontLinger,sizeof(BOOL));
closesocket(s);
//MFC CAsyncSocket或者CSocket
BOOL bDontLinger=FALSE;
m_socket->SetSockOpt(SO_DONTLINGER,(const char *)&bDontLinger,sizeof(bDontLinger),SOL_SOCKET);
m_socket->Close();