我有一臺服務器使用雙線程系統來管理100到200個併發連接。它使用TCP套接字,因爲數據包傳輸保證很重要(這是一個通信系統,在這種系統中,未能通過遠程API調用FUBAR客戶端)。Windws C++間歇性套接字斷開連接
我已經實現了一個自定義協議層,將傳入的字節分成數據包並正確分發它們(庫包含在下面)。我意識到使用MSG_PEEK的問題,但就我所知,它是唯一能夠滿足庫實現需求的系統。我願意接受建議,特別是如果這可能是問題的一部分。
基本上,問題是,儘管客戶端每隔4次成功發送一次keepalive數據包,但由於缺少傳入數據包的時間超過20秒,服務器將隨機丟棄客戶端的套接字。我可以驗證服務器本身沒有脫機,並且遇到問題的用戶(包括我自己)的連接穩定。
用於發送該庫/接收是在這裏:
short ncsocket::send(wstring command, wstring data) {
wstringstream ss;
int datalen = ((int)command.length() * 2) + ((int)data.length() * 2) + 12;
ss << zero_pad_int(datalen) << L"|" << command << L"|" << data;
int tosend = datalen;
short __rc = 0;
do{
int res = ::send(this->sock, (const char*)ss.str().c_str(), datalen, NULL);
if (res != SOCKET_ERROR)
tosend -= res;
else
return FALSE;
__rc++;
Sleep(10);
} while (tosend != 0 && __rc < 10);
if (tosend == 0)
return TRUE;
return FALSE;
}
short ncsocket::recv(netcommand& nc) {
vector<wchar_t> buffer(BUFFER_SIZE);
int recvd = ::recv(this->sock, (char*)buffer.data(), BUFFER_SIZE, MSG_PEEK);
if (recvd > 0) {
if (recvd > 8) {
wchar_t* lenstr = new wchar_t[4];
memcpy(lenstr, buffer.data(), 8);
int fulllen = _wtoi(lenstr);
delete lenstr;
if (fulllen > 0) {
if (recvd >= fulllen) {
buffer.resize(fulllen/2);
recvd = ::recv(this->sock, (char*)buffer.data(), fulllen, NULL);
if (recvd >= fulllen) {
buffer.resize(buffer.size() + 2);
buffer.push_back((char)L'\0');
vector<wstring> data = parsewstring(L"|", buffer.data(), 2);
if (data.size() == 3) {
nc.command = data[1];
nc.payload = data[2];
return TRUE;
}
else
return FALSE;
}
else
return FALSE;
}
else
return FALSE;
}
else {
::recv(this->sock, (char*)buffer.data(), BUFFER_SIZE, NULL);
return FALSE;
}
}
else
return FALSE;
}
else
return FALSE;
}
這是用於確定是否太多時間已經過去的代碼:
if ((int)difftime(time(0), regusrs[i].last_recvd) > SERVER_TIMEOUT) {
regusrs[i].sock.end();
regusrs[i].is_valid = FALSE;
send_to_all(L"removeuser", regusrs[i].server_user_id);
wstringstream log_entry;
log_entry << regusrs[i].firstname << L" " << regusrs[i].lastname << L" (suid:" << regusrs[i].server_user_id << L",p:" << regusrs[i].parent << L",pid:" << regusrs[i].parentid << L") was disconnected due to idle";
write_to_log_file(server_log, log_entry.str());
}
的「regusrs [I ]「正在使用我用來描述套接字描述符和用戶信息的向量的當前迭代成員。 'is_valid'檢查可以告訴關聯用戶是否是實際用戶 - 這樣做是爲了防止系統不得不釋放向量的成員 - 它只是將其返回到可用槽的池中。沒有線程訪問/超出範圍的問題。
無論如何,我開始懷疑是否服務器本身就是問題所在。我目前正在另一臺服務器上進行測試,但我想知道是否有另一組眼睛可以阻止某些不合適的位置,或者提示我插入一個概念,並使用我不知道的擴展Keepalive。
在此先感謝!
首先做循環是越野車;如果初始發送沒有接收到所有數據,則從頭開始再次發送,而不僅僅是第一次發送的數據。不確定這是否解釋了問題。你如何發送Keepalive數據包?你是否檢查過電線上的數據以確保它們實際上是及時傳輸的? – 2014-10-07 02:02:24
我還沒有檢查線路上的線路,因爲我無法可靠地重新創建線路。我已連接到服務器(因爲我開始在不同的機器上託管它)連續幾個小時。我認爲服務器更改和切換MSG_PEEK的組合將有所幫助。 – 2014-10-07 04:21:06