我有一个使用winsock2的简单阻塞服务器/客户端应用程序,运行简单的异步clientHandler。我们的想法是将一个开放的连接作为机器人应用程序的keepalive标志。
套接字(客户端和服务器)的初始化并在它们之间建立连接工作正常,但是在接收到8条消息之后,接收到的那些关闭了连接(错误10053),导致发送方出现错误10054.此时它没有如果我手动发送所有消息(例如每分钟1次)或自动发送消息,则无关紧要。如果对方在消息之间进行回复并不重要,结果总是相同的。
消息由两部分组成,标题包含元信息(id,command,payloadLength,以字节为单位)和acutal payload(如果有)。令人费解的部分是:我需要发送比sizeof()更多的1个字节,否则对方不起作用。
到目前为止,我试过了:
select()
的输出
在收件人设置RST
标志的邮件限制之前,一切都看起来不错。客户端和服务器的输入/输出缓冲区设置为65kb,我的消息甚至没有接近。此外,当我每封邮件发送大量数据集(50kb)时也会发生这种情况。 8个消息后,连接就会消失。
我认为错误在套接字的配置中显而易见,但是我无法弄清楚在哪里,所以任何帮助或提示都非常适合,因为错误10054是非常暧昧的,没有很多帮助。< / p>
以下是配置服务器/客户端和接收/发送消息的一些代码段。为了便于阅读,我不在此处添加任何错误检查:
//Server
//Init
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
struct sockaddr_in config;
config.sin_family = AF_INET;
config.sin_addr.s_addr = INADDR_ANY;
config.sin_port = htons(8080);
Socket m_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//set server to a state where it accepts incoming connections
bind(m_sock, (sockaddr *)&config, sizeof(sockaddr_in));
listen(m_sock, 100);
int c = sizeof(struct sockaddr_in);
//block until new client connects
Socket m_client = accept(m_sock, (sockaddr*)client, &c));
//handling and awaiting the client messages would have happend asyncronously with the m_client pointers swapped etc.
//receive data
struct msgHeader{
short id;
short command;
short payloadLength;
}
msgHeader* head = new msgHeader;
int error = 0;
do {
err = recv(*client, (char*)head, headerSize, SD_RECEIVE);
if (err == headerSize)
{
if (head->payloadLength > 0)
{
char* payload = new char[head->payloadLength]{0};
err = recv(*client, payload, head->payloadLength, SD_RECEIVE); // SERVER DIES HERE!!
if (err == head->payloadLength)
{
// callback is happening here
}
else
{
// error occured
}
}
}
} while (err > 0);
delete head;
closesocket(m_sock);
WSACleanup();
至于客户:
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa));
m_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
m_serverConfig.sin_addr.s_addr = inet_addr("127.0.0.1");
m_serverConfig.sin_family = AF_INET;
m_serverConfig.sin_port = htons("8080");
connect(m_sock, (struct sockaddr *)&m_serverConfig, sizeof(sockaddr_in));
std::string msg = "Hello from client";
msgHeader head{ 23, 0, msg.size() };
while(true)
{
send(m_sock, (char*)&head, sizeof(msgHeader) + 1, SD_SEND); //this +1 offset irretates me since I'm trying to send raw data. sizeof returns 6 which is ok only if I send 7 bytes the server receives 6 thus the complete header.
send(m_sock, msg.c_str(), msg.size() + 1, SD_SEND)); // CLIENT DIES HERE AFTER THE 8th iteration!!
}
//closesocket()... wsacleanup etc...
如果您需要整个代码,我会公开回购并发布链接。
到目前为止,感谢并希望有人有一个工作建议,在哪里寻找错误。
编辑: 客户端和服务器的代码+编译它所需的一切(阁楼项目)可以在这里找到: Code
答案 0 :(得分:0)
我在这段代码中看到了很多错误,其中最少的错误是错误/错误处理不足。
尝试更多类似的内容。
服务器:
WSADATA wsa;
int res = WSAStartup(MAKEWORD(2, 2), &wsa);
if (res != 0) {
// error handling ...
}
SOCKET m_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_sock == INVALID_SOCKET) {
// error handling ...
}
struct sockaddr_in config = {0};
config.sin_family = AF_INET;
config.sin_addr.s_addr = INADDR_ANY;
config.sin_port = htons(8080);
if (bind(m_sock, (sockaddr *)&config, sizeof(config)) == SOCKET_ERROR) {
// error handling ...
}
if (listen(m_sock, 100) == SOCKET_ERROR) {
// error handling ...
}
struct sockaddr_in client = {0};
int c = sizeof(client);
SOCKET m_client = accept(m_sock, (sockaddr*)&client, &c);
if (m_client == INVALID_SOCKET) {
// error handling...
}
...
#pragma pack(push, 1) // or your compiler's equivalent
struct msgHeader {
short id;
short command;
short payloadLength;
};
#pragma pack(pop)
int recvAll(SOCKET s, void *buf, int buflen)
{
int res = recv(s, buf, buflen, MSG_WAITALL);
if ((res != SOCKET_ERROR) || (WSAGetLastError() != WSAEOPNOTSUPP)) {
return res;
}
char *pbuf = (char*) buf;
int len = buflen;
while (len > 0) {
res = recv(s, buf, len, 0);
if (res <= 0) {
return res;
}
pbuf += res;
len -= res;
}
return buflen;
}
msgHeader head;
std::vector<char> payload;
int res;
do {
res = recvAll(*client, &head, sizeof(head));
if (res <= 0) {
if (res == SOCKET_ERROR) {
// error handling ...
} else {
// client disconnected
}
break;
}
head.id = htons(head.id);
head.command = htons(head.command);
head.payloadLength = htons(head.payloadLength);
if (head.payloadLength > 0)
{
payload.resize(head.payloadLength);
res = recvAll(*client, &payload[0], head.payloadLength);
if (res <= 0) {
if (res == SOCKET_ERROR) {
// error handling ...
} else {
// client disconnected
}
break;
}
}
// callback happens here ...
callback(&head, payload.data());
payload.clear();
}
while (true);
closesocket(*client);
...
closesocket(m_sock);
WSACleanup();
客户端:
#pragma pack(push, 1) // or your compiler's equivalent
struct msgHeader {
short id;
short command;
short payloadLength;
};
#pragma pack(pop)
bool sendAll(SOCKET s, const void *buf, int buflen)
{
const char *pbuf = (const char*) buf;
while (buflen > 0) {
int res = send(s, pbuf, buflen, 0);
if (res == SOCKET_ERROR) {
return false;
}
pbuf += res;
len -= res;
}
return true;
}
...
WSADATA wsa;
int res = WSAStartup(MAKEWORD(2, 2), &wsa);
if (res != 0) {
// error handling...
}
m_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_sock == INVALID_SOCKET) {
// error handling...
}
m_serverConfig.sin_addr.s_addr = inet_addr("127.0.0.1");
m_serverConfig.sin_family = AF_INET;
m_serverConfig.sin_port = htons("8080");
if (connect(m_sock, (struct sockaddr *)&m_serverConfig, sizeof(m_serverConfig)) == SOCKET_ERROR) {
// error handling...
}
std::string msg = "Hello from client";
const msgHeader head{ htons(23), 0, htons(msg.size()) };
do {
if (!sendAll(m_sock, &head, sizeof(head))) {
// error handling...
break;
}
if (!sendAll(m_sock, msg.c_str(), msg.size())) {
// error handling...
break;
}
}
while (true);
closesocket(m_sock);
WSACleanup();