這幾天想在一個開源的代碼上進行修改,以期研發出一個產品出來。
程序原來是單線程網絡程序,需要修改為多線程,修改之後,總是出問題,輔助線程中的recv函數總是運行一陣子之後收到長度為-1的數據報,導致程序運行不正確甚至崩潰。
由於是多線程,只好打日志進行調試,發現一個奇怪的問題。在A線程與B線程中,均使用了socket這個函數來產生socket,竟然會產生兩個相同返回值的socket!也就是說,A線程與B線程能同時獲得socket值為360的socket,這樣當A正在使用360進行數據接收時,B去連接一把,A自然就出錯了。
這個問題實在是詭異,因為socket又不是COM組件,是可以直接在線程中共享的,究竟是出了什麼問題呢,MSDN和網絡上沒有見到任何與此問題相關的內容。活脫脫地就是API出錯了!按道理這是不可能的事情啊。
實在沒轍了,只好review代碼,發現程序中有很多這樣的語句:
if( mSocket != INVALID_SOCKET )
{
closesocket( mSocket );
}
這句有什麼問題沒有?呵呵看起來沒什麼問題,但是,不容置疑的是,肯定會導致一個socket被關閉多次。本著死馬當著活馬醫的原則,進行修改,每次closesocket之後,將socket的值置為INVALID_SOCKET,運行程序,問題解決。
這個問題也太ft了,windows竟然連這個容錯都沒有做,按道理這是很好做的,socket實際上只是一個索引值,系統內核在關閉時如果發現已經關閉就不要做操作就可以了。現在看起來,內核裡面貌似是一個socket緩沖池,程序在使用的時候使用計數來管理生命周期。這樣當一個socket被關閉多次後,再創建改socket之後,系統可能會認為該socket是關閉的(因為計數小於等於0)。所以下次分配的時候,會將該索引重新分配出去。
該問題在vista home版上出現,其他平台又沒有問題不得而知,由此可以看出成對編碼的好處以及面向對象封裝的好處。
轉自:http://blog.csdn.net/chen495810242/article/details/42029825
個人注釋:在win7上的測試結果,當一個工程調用多個dll的時候,不同的dll之間使用socket這個函數來產生socket,返回值是可能一樣的,就會發生連接無緣無故被斷開的現象,查了兩三天的說