Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在tcp服务器等待数据时,如何使程序每10毫秒读取一次传感器_C_Multithreading_Sockets_Tcp - Fatal编程技术网

在tcp服务器等待数据时,如何使程序每10毫秒读取一次传感器

在tcp服务器等待数据时,如何使程序每10毫秒读取一次传感器,c,multithreading,sockets,tcp,C,Multithreading,Sockets,Tcp,我的程序需要每10毫秒读取一次传感器数据,并通过TCP套接字将其发送给客户端。程序是用C语言编写的。tcp服务器和传感器读取代码位于同一个c文件中。服务器不定期发送数据。相反,它等待来自客户端的数据请求(每50毫秒一次)。一旦服务器接收到请求,它就向客户端发送数据 我的问题是,我需要每隔10毫秒读取一次传感器,并将其保存在缓冲区中。服务器收到请求后,将缓冲区中的传感器数据发送给客户端。但当tcp服务器等待请求时,整个程序都卡在读取功能上: n = read(newsockfd,buffer,31

我的程序需要每10毫秒读取一次传感器数据,并通过TCP套接字将其发送给客户端。程序是用C语言编写的。tcp服务器和传感器读取代码位于同一个c文件中。服务器不定期发送数据。相反,它等待来自客户端的数据请求(每50毫秒一次)。一旦服务器接收到请求,它就向客户端发送数据

我的问题是,我需要每隔10毫秒读取一次传感器,并将其保存在缓冲区中。服务器收到请求后,将缓冲区中的传感器数据发送给客户端。但当tcp服务器等待请求时,整个程序都卡在读取功能上:

n = read(newsockfd,buffer,31)
那么,我就看不清传感器了

我尝试使用线程来读取传感器和tcp服务器。它适用于读取传感器。但是,如果我在tcp服务器线程中添加任何usleep(),例如5毫秒,则需要5毫秒才能将数据发送到客户端

我的程序需要tcp服务器在收到请求后立即向客户端发送数据。同时,每10毫秒读取一次传感器。谁有更好的解决方案

tcp服务器和传感器读取的代码如下:

#include <stdio.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>

#define MAX_SIZE 256
#define SAMPLE_RATE 



void read_sensor(void) {
    printf("read sensors\n");
}


int main() {

     int sockfd, newsockfd, portno = 10000, clilen;
     char buffer[MAX_SIZE];
     struct sockaddr_in serv_addr, cli_addr;
     int n;
     int data;

     printf( "using port #%d\n", portno );

     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0) 
         printf("ERROR opening socket\n");
     bzero((char *) &serv_addr, sizeof(serv_addr));

     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons( portno );
     if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
       error( const_cast<char *>( "ERROR on binding" ) );
     listen(sockfd,5);
     clilen = sizeof(cli_addr);

     while (1) {
        printf( "waiting for new client...\n" );
        if ( ( newsockfd = accept( sockfd, (struct sockaddr *) &cli_addr, (socklen_t*) &clilen) ) < 0 )
            printf("ERROR on accept");
        printf( "opened new communication with client\n" );

        clock_gettime(CLOCK_REALTIME, &gettime_now);
        start_time = gettime_now.tv_nsec;       //Get nS value
        while (1) {
             int n = 0;
             if ( (n = read(newsockfd,buffer,31) ) < 0 ) //read data
                printf("ERROR reading from socket");
             buffer[n] = '\0';

             if (n > 0)
                printf("%s\n", buffer);
             else {
                break;             
             }

             if ( (n = write( newsockfd, buffer, strlen(buffer) ) ) < 0 ) //send data
                printf( "ERROR writing to socket\n");
             buffer[n] = '\0';

        }
        close( newsockfd );
     }


     return 0; 
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义最大尺寸256
#定义抽样率
无效读取传感器(无效){
printf(“读取传感器”);
}
int main(){
int sockfd,newsockfd,端口号=10000,clilen;
字符缓冲区[最大大小];
服务地址中的结构sockaddr\u,cli\u addr;
int n;
int数据;
printf(“使用端口#%d\n”,端口号);
sockfd=套接字(AF_INET,SOCK_STREAM,0);
if(sockfd<0)
printf(“打开套接字时出错\n”);
bzero((char*)&serv_addr,sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=INADDR_ANY;
serv_addr.sin_port=htons(端口号);
if(bind(sockfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr))<0)
错误(const_cast(“绑定错误”);
听(sockfd,5);
clilen=sizeof(cli_addr);
而(1){
printf(“等待新客户端…\n”);
if((newsockfd=accept(sockfd,(struct sockaddr*)和cli_addr,(socklen_t*)和clilen))<0)
printf(“接受错误”);
printf(“打开了与客户端的新通信\n”);
clock\u gettime(clock\u REALTIME和gettime\u now);
start\u time=gettime\u now.tv\u nsec;//获取nS值
而(1){
int n=0;
如果((n=read(newsockfd,buffer,31))<0)//读取数据
printf(“从套接字读取错误”);
缓冲区[n]='\0';
如果(n>0)
printf(“%s\n”,缓冲区);
否则{
打破
}
if((n=write(newsockfd,buffer,strlen(buffer)))<0)//发送数据
printf(“写入套接字时出错\n”);
缓冲区[n]='\0';
}
关闭(newsockfd);
}
返回0;
}
您可以使用或等待数据到达,但需要超时

例如,如果您需要从现在起5毫秒读取传感器,您可以调用
poll
select
,超时时间为5毫秒。如果套接字接收到数据,它将立即返回并告诉您。否则,它将在5毫秒后返回,您将知道没有数据

轮询的示例

struct pollfd pollfd = {.fd = socket_fd, .events = POLLIN};
int err = poll(&pollfd, 1, milliseconds_timeout);
// error check here; if err is negative then the error code is in errno
if (pollfd.revents & POLLIN) {
    // Socket received data
}
// Otherwise it didn't.
// Note that if data was received, it might not be time to read the sensors yet.
// You should keep poll()ing until it's the right time to read the sensors, using clock_gettime to check the time.
您可以使用或等待数据到达,但需要超时

例如,如果您需要从现在起5毫秒读取传感器,您可以调用
poll
select
,超时时间为5毫秒。如果套接字接收到数据,它将立即返回并告诉您。否则,它将在5毫秒后返回,您将知道没有数据

轮询的示例

struct pollfd pollfd = {.fd = socket_fd, .events = POLLIN};
int err = poll(&pollfd, 1, milliseconds_timeout);
// error check here; if err is negative then the error code is in errno
if (pollfd.revents & POLLIN) {
    // Socket received data
}
// Otherwise it didn't.
// Note that if data was received, it might not be time to read the sensors yet.
// You should keep poll()ing until it's the right time to read the sensors, using clock_gettime to check the time.

允许每个线程彼此独立运行。传感器读取线程不需要与客户端请求线程交互。您确定它需要“立即”进行传输吗?因为对于人眼来说,100毫秒以内的一切都可以被认为是“即时的”<代码>虽然(1)是一种不好的做法,但要设置一个明显的退出条件,覆盖更高级别的实用程序中的所有丑陋之处,以便“弹出”问题。通常,您可以使用类似于
select()
的函数来查询是否有可用数据。在我最近的应用程序中,我实际上使用了get_available_bytes之类的函数。仔细考虑你的网络体系结构。注意,一个坏的网络连接可能导致往返时间超过10ms。您真的需要交付所有传感器数据包吗?如果一些被丢弃、延迟或出现故障(并且可以被接收器丢弃),可以吗?然后考虑使用UDP而不是TCP,这样您就可以发送传感器包,而不必等待答复。<代码>写(NeXSOCFD,缓冲器,STRLEN(缓冲器))< />也有问题,因为TCP连接是流,没有数据包边界的保护。如果您每10毫秒发送一次,并且在连接上发生了一些事情,那么在接收器读取数据包之前,数据包可能会合并在一起,并且来自多个数据包的数据会合并为一个
read()
。如果没有什么不好的事情发生,数据包可以被合并。而且字符串也可以拆分为多个数据包。通常,一些最佳做法是发送频率永远不要超过接收频率,始终检查发送和接收值,始终接收固定大小的数据包,该数据包告诉您至少两件事情,即预期的数据ID和大小,并且可能使用一个队列以可预测的方式调度发送方的数据。您可以在线程或在有数据可用时调用async recv命令的线程中设置阻塞接收(注意超时)(请参阅,例如
select()
)以允许每个线程独立运行。传感器读数为thr