我有一台服务器使用双线程系统来管理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