TCP 需要丢弃缓冲区上的信息或使其更快
TCP need to discard info on the buffer or make it faster
我正在制作一个 3d 应用程序,它可以处理手机的加速度计和陀螺仪的数据。问题在于手机发送数据的速度比计算机读取数据的速度快。随着时间的流逝,该应用程序越来越多地使移动设备的移动具有更多延迟。比如一开始2~3s是忠实于手机在现实中做的动作,但是超过10s就是我6秒前做的动作
我知道它正在从起始缓冲区读取数据,而最新数据的前端会增长并且永远不会到达它。我认为问题在于我如何读取传来的数据。
这是在应用程序中实现的示例代码。我能做什么?
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <fcntl.h>
#include <algorithm>
#define PORT 8080
int main(int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = {0};
const char *ACK = "ACKDAT\n";
std::string data;
socklen_t len;
char *error;
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,&opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
fcntl(new_socket, F_SETFL, O_NONBLOCK);
while(true){
valread = read( new_socket , buffer, 1024);
for(int i = 0;i < 1024 ; i++){
if(buffer[i]!=0){
data = data + buffer[i];
}
buffer[i]=0;
}
if(!data.empty()){
//remove /n from data
data.erase(std::remove(data.begin(), data.end(), '\n'), data.end());
std::cout<<"#"<<data<<"#"<<std::endl;
send(new_socket , ACK , strlen(ACK) , 0 );
}
data.clear();
}
return 0;
}
您可以在单独的 std::thread
中完成所有从套接字的读取,除了从套接字读取并将数据保存在程序的内部缓冲区中之外什么都不做。只要有能力,您现有的程序就会从内部缓冲区而不是套接字中读取。
如果内部缓冲区已满,您将不得不想办法解决它,可能会丢弃不需要的数据。也许将最近收到的记录的副本存放在安全的地方,并在事情畅通时将其放入缓冲区。专用执行线程可能需要做一些最少的处理,将来自套接字的原始数据解析为某种有意义的逻辑形式。您不太可能简单地从套接字中丢弃原始数据流的随机部分。它需要以您的应用程序特有的某种形式或方式进行逻辑解析,因此可以以有意义的方式完成。
您需要以 thread-safe 方式实现应用程序的缓冲区,以便多个执行线程可以同时访问它。如果您不熟悉 multi-threaded C++ 编程,您可以在 C++ 教科书中找到有关此主题的更多信息。
虽然 Sam Varshavchik 关于使用线程的建议很好,但还有另一种选择。
您已经将套接字设置为 non-blocking 和 fcntl(new_socket, F_SETFL, O_NONBLOCK);
。因此,在每个循环中,您应该阅读所有要阅读的内容并发送所有要发送的内容。不打平one-to-one读写,两边都能赶上
您需要解决此问题的主要提示是您没有使用 read
return 值 valread
。您的代码应如下所示:
while(true){ // main loop
...
valread = read( new_socket , buffer, 1024);
while(valread > 0)
{
// deal with the read values.
// deal with receiving more than one packet per iteration
}
// send code done a single time per loop.
您仍然需要大量的体系结构来拥有一个干净的、有弹性的发送和接收主循环,但我希望这能为您指明一个有用的方向。
我正在制作一个 3d 应用程序,它可以处理手机的加速度计和陀螺仪的数据。问题在于手机发送数据的速度比计算机读取数据的速度快。随着时间的流逝,该应用程序越来越多地使移动设备的移动具有更多延迟。比如一开始2~3s是忠实于手机在现实中做的动作,但是超过10s就是我6秒前做的动作
我知道它正在从起始缓冲区读取数据,而最新数据的前端会增长并且永远不会到达它。我认为问题在于我如何读取传来的数据。
这是在应用程序中实现的示例代码。我能做什么?
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <fcntl.h>
#include <algorithm>
#define PORT 8080
int main(int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = {0};
const char *ACK = "ACKDAT\n";
std::string data;
socklen_t len;
char *error;
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,&opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
fcntl(new_socket, F_SETFL, O_NONBLOCK);
while(true){
valread = read( new_socket , buffer, 1024);
for(int i = 0;i < 1024 ; i++){
if(buffer[i]!=0){
data = data + buffer[i];
}
buffer[i]=0;
}
if(!data.empty()){
//remove /n from data
data.erase(std::remove(data.begin(), data.end(), '\n'), data.end());
std::cout<<"#"<<data<<"#"<<std::endl;
send(new_socket , ACK , strlen(ACK) , 0 );
}
data.clear();
}
return 0;
}
您可以在单独的 std::thread
中完成所有从套接字的读取,除了从套接字读取并将数据保存在程序的内部缓冲区中之外什么都不做。只要有能力,您现有的程序就会从内部缓冲区而不是套接字中读取。
如果内部缓冲区已满,您将不得不想办法解决它,可能会丢弃不需要的数据。也许将最近收到的记录的副本存放在安全的地方,并在事情畅通时将其放入缓冲区。专用执行线程可能需要做一些最少的处理,将来自套接字的原始数据解析为某种有意义的逻辑形式。您不太可能简单地从套接字中丢弃原始数据流的随机部分。它需要以您的应用程序特有的某种形式或方式进行逻辑解析,因此可以以有意义的方式完成。
您需要以 thread-safe 方式实现应用程序的缓冲区,以便多个执行线程可以同时访问它。如果您不熟悉 multi-threaded C++ 编程,您可以在 C++ 教科书中找到有关此主题的更多信息。
虽然 Sam Varshavchik 关于使用线程的建议很好,但还有另一种选择。
您已经将套接字设置为 non-blocking 和 fcntl(new_socket, F_SETFL, O_NONBLOCK);
。因此,在每个循环中,您应该阅读所有要阅读的内容并发送所有要发送的内容。不打平one-to-one读写,两边都能赶上
您需要解决此问题的主要提示是您没有使用 read
return 值 valread
。您的代码应如下所示:
while(true){ // main loop
...
valread = read( new_socket , buffer, 1024);
while(valread > 0)
{
// deal with the read values.
// deal with receiving more than one packet per iteration
}
// send code done a single time per loop.
您仍然需要大量的体系结构来拥有一个干净的、有弹性的发送和接收主循环,但我希望这能为您指明一个有用的方向。