在无块模式下处理随机数据大小的接收
Handling recv of Random Data Sizes In no-block Mode
我敢肯定这个问题以前有人问过,也许它只是隐藏在 Google 结果或 Whosebug 中的某个地方。但到目前为止,我已经设置了一个非阻塞缓存服务器。这适用于小消息或数据。但是,如果客户端尝试发送大量数据怎么办?在我使用每个客户端设置的阻塞线程之前,我使用了一个定界符来告诉数据包在哪里结束。在意识到由于硬件限制此路由不可靠之后。因此,如果可能的话,我将采用单线程方法。
基本上,我想知道如何执行 recv 来捕获附加到单个缓冲区中的数据包,以便在用户发送完数据后使用?
我的一个想法就是像往常一样简单地进行 recv。如果找不到定界符,则将 recv 分叉到一个线程中,然后将数据加到某个缓冲区中。
I.E
struct tempBuffer{
int socket;
std::string buffer;
bool isDone;
};
std::vector<tempBuffer> temp;
...
if !findDelimiter(recvResponseData)
startThread(collectData, socket);
这是我的 recvAll 的样子:
std::string swiss_cache::recvAll(int socket, bool &quit) {
std::string buffer;
size_t sentBuffer = 0;
quit = false;
//now it is time to receive the page
while(true)
{
char buf[CHUNK_SIZE+1];
memset(buf, 0, strlen(buf));
size_t tmpres = recv(socket, buf, CHUNK_SIZE, 0);
if(tmpres == 0){
quit = true;
return buffer;
}
buffer += (const char*)buf;
if(findEscapeKey(buffer)) { /* FOUND ESCAPE KEYWORD TO LEAVE RECV */
return buffer;
}
}
return buffer;
} /* recvAll */
当客户端需要发送多个数据包时,如何在无阻塞模式下从客户端收集单个缓冲区中的数据包?
这归结为如何在单个线程内处理多个套接字上的通信的问题。传统的解决方案是使用 select()
或 poll()
系统调用,它们获取感兴趣的文件描述符集,并且 return 包含有关哪些描述符已准备好读取数据的信息。
使用 select()
,数据处理循环如下所示:
Zero read-set of file descriptors.
For each client:
add client socket to read-set if client not done.
Call select() on read-set.
# read-set now contains file descriptors with pending data
For each file descriptor in the read-set:
Find the corresponding client.
Do recv() operation on the file descriptor.
Update 'done' status for the client if delimiter found.
Process complete data for the client.
逻辑与 poll()
相似。
TCP 是一种流式传输协议。它不知道您期望有多少数据,也无法判断另一端何时停止写入;您只是在收到时获得传递的数据。何时拥有所有数据取决于您。
您必须继续进行读取并将接收到的内容组合到一个缓冲区中,然后在获得所需的一切后对其进行操作。处理收到的超出预期的情况也很重要;如果您要发送多条消息,最后的阅读可能包含一条消息的结尾和另一条消息的开头。
计算您需要多少数据的一种常见方法是随每条消息发送 header,包括消息包含多少字节。你也可以像你想的那样使用分隔符,只要你能保证分隔符不会出现在消息内容中即可。
我敢肯定这个问题以前有人问过,也许它只是隐藏在 Google 结果或 Whosebug 中的某个地方。但到目前为止,我已经设置了一个非阻塞缓存服务器。这适用于小消息或数据。但是,如果客户端尝试发送大量数据怎么办?在我使用每个客户端设置的阻塞线程之前,我使用了一个定界符来告诉数据包在哪里结束。在意识到由于硬件限制此路由不可靠之后。因此,如果可能的话,我将采用单线程方法。
基本上,我想知道如何执行 recv 来捕获附加到单个缓冲区中的数据包,以便在用户发送完数据后使用?
我的一个想法就是像往常一样简单地进行 recv。如果找不到定界符,则将 recv 分叉到一个线程中,然后将数据加到某个缓冲区中。
I.E
struct tempBuffer{
int socket;
std::string buffer;
bool isDone;
};
std::vector<tempBuffer> temp;
...
if !findDelimiter(recvResponseData)
startThread(collectData, socket);
这是我的 recvAll 的样子:
std::string swiss_cache::recvAll(int socket, bool &quit) {
std::string buffer;
size_t sentBuffer = 0;
quit = false;
//now it is time to receive the page
while(true)
{
char buf[CHUNK_SIZE+1];
memset(buf, 0, strlen(buf));
size_t tmpres = recv(socket, buf, CHUNK_SIZE, 0);
if(tmpres == 0){
quit = true;
return buffer;
}
buffer += (const char*)buf;
if(findEscapeKey(buffer)) { /* FOUND ESCAPE KEYWORD TO LEAVE RECV */
return buffer;
}
}
return buffer;
} /* recvAll */
当客户端需要发送多个数据包时,如何在无阻塞模式下从客户端收集单个缓冲区中的数据包?
这归结为如何在单个线程内处理多个套接字上的通信的问题。传统的解决方案是使用 select()
或 poll()
系统调用,它们获取感兴趣的文件描述符集,并且 return 包含有关哪些描述符已准备好读取数据的信息。
使用 select()
,数据处理循环如下所示:
Zero read-set of file descriptors.
For each client:
add client socket to read-set if client not done.
Call select() on read-set.
# read-set now contains file descriptors with pending data
For each file descriptor in the read-set:
Find the corresponding client.
Do recv() operation on the file descriptor.
Update 'done' status for the client if delimiter found.
Process complete data for the client.
逻辑与 poll()
相似。
TCP 是一种流式传输协议。它不知道您期望有多少数据,也无法判断另一端何时停止写入;您只是在收到时获得传递的数据。何时拥有所有数据取决于您。
您必须继续进行读取并将接收到的内容组合到一个缓冲区中,然后在获得所需的一切后对其进行操作。处理收到的超出预期的情况也很重要;如果您要发送多条消息,最后的阅读可能包含一条消息的结尾和另一条消息的开头。
计算您需要多少数据的一种常见方法是随每条消息发送 header,包括消息包含多少字节。你也可以像你想的那样使用分隔符,只要你能保证分隔符不会出现在消息内容中即可。