使用 UDP 中断 while()-循环

Break while()-loop using UDP

本文关键字:循环 while UDP 中断 使用      更新时间:2023-10-16

是否可以在while()循环中执行一些工作,例如递增计数器,然后用UDP消息中断此while()循环?

我有一个Raspberry Pi 4,它被设置为UDP服务器。我使用的编程语言是C++。UDP.hpp:

#pragma once
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string>
#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <netdb.h>
using namespace std;
/////GLOBAL CONSTANTS/////
const int c_PORT = 8080;
class UDP
{
private:
int fdSocketUDP_;                  //File descriptor for UDP socket
int ClientAddressLength_;          //Length of client address
struct sockaddr_in ServerAddress_; //Struct handling internet address for server
struct sockaddr_in ClientAddress_; //Struct handling internet address for client
public:
UDP();                              //Initialize and bind socket
~UDP();                             //Close socket
string readUDP(const int readSize); //Read via UDP protocol (Only for blocking socket)
void writeUDP(string message);      //Write via UDP protocol (Only for blocking socket)
};

UDP.cpp:

#include "udp.hpp"
UDP::UDP()
{
if ((fdSocketUDP_ = socket(AF_INET, SOCK_DGRAM, 0)) < 0) //Create UDP socket
{
perror("Error - socket creation - udp.cpp");
exit(EXIT_FAILURE);
}
memset(&ServerAddress_, 0, sizeof(ServerAddress_)); //Sets ServerAddress_ to 0
memset(&ClientAddress_, 0, sizeof(ClientAddress_)); //Sets ClientAddress_ to 0
ServerAddress_.sin_family = AF_INET;         //Address family, must be AF_INET = IPv4
ServerAddress_.sin_port = htons(c_PORT);     //PORT number, convert PORT number to network byte order using htons()
ServerAddress_.sin_addr.s_addr = INADDR_ANY; //IP-Address of host (server IP), INADDR_ANY gets this IP Address
if (bind(fdSocketUDP_, (const struct sockaddr *)&ServerAddress_, sizeof(ServerAddress_)) < 0) //Bind the socket to ServerAddress_
{
perror("Error - socket bind - udp.cpp");
exit(EXIT_FAILURE);
}
}
UDP::~UDP()
{
close(fdSocketUDP_); //Close socket
}                    
string UDP::readUDP(const int readSize)
{
char readMsg[readSize] = {0}; //Read buffer
ClientAddressLength_ = sizeof(ClientAddress_);
if ((recvfrom(fdSocketUDP_, readMsg, readSize, 0, (struct sockaddr *)&ClientAddress_, (socklen_t *)&ClientAddressLength_)) < 0) //Receive data via UDP protocol
{
perror("Error - recvfrom - udp.cpp");
exit(EXIT_FAILURE);
}
string str(readMsg);           //Convert char array to string
str = str.substr(0, readSize); //Make sure the string is the length of readsize
return str;
}
void UDP::writeUDP(string message)
{
//Make char array 
int writeSize = message.size();
char writeMsg[writeSize + 1] = {''};
//Convert string message to char array
for (int i = 0; i < writeSize; i++)
{
writeMsg[i] = message[i];
}
if ((sendto(fdSocketUDP_, writeMsg, writeSize, 0, (const struct sockaddr *)&ClientAddress_, (socklen_t)ClientAddressLength_)) < 0) //Send data via UDP protocol
{
perror("Error - sendto - udp.cpp");
exit(EXIT_FAILURE);
}
}

我有一台笔记本电脑,运行Labview程序。它充当 UDP 客户端。通过从笔记本电脑向 RPi 发送数据,我希望能够通过 UDP 发送特定数据来打破main()函数中的 while 循环。

假设我从笔记本电脑向 RPi 发送"111"数据。然后,RPi 进入main()函数中的while()循环,做一些工作。我希望 RPi 保持在这个while()循环中,直到我从笔记本电脑发送特定数据。假设我想打破这个while()循环的数据是"999"。

使用 UDP 可以这样做吗?

当然。只需将套接字设置为非阻塞,并定期检查套接字上是否收到数据。如果有,请检查它是否是停止命令,如果是,则停止。您可以检查循环的每次迭代,或者,如果循环重复得非常快,则每 10 次或每 100 次迭代一次。

多亏了洛恩和@David施瓦茨的@Marquis,我解决了我的问题。解决方案是使用 fcntl 并将套接字设置为非阻塞。

我已将 UDP.hpp 更新为:

#pragma once
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string>
#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <netdb.h>
#include <sys/unistd.h>
#include <sys/fcntl.h>
using namespace std;
/////GLOBAL CONSTANTS/////
const int c_PORT = 8080;
class UDP
{
private:
int fdSocketUDP_;                  //File descriptor for UDP socket
int ClientAddressLength_;          //Length of client address
struct sockaddr_in ServerAddress_; //Struct handling internet address for server
struct sockaddr_in ClientAddress_; //Struct handling internet address for client
public:
UDP();                              //Initialize and bind socket
~UDP();                             //Close socket
void initNonBlock();                     //Initialize and bind socket (non blocking)
void initBlock();                        //Initialize and bind socket (blocking)
void closeSocket();                            //Close socket
string readNonBlock(const int readSize);                     //read via UDP protocol with non blocking socket
string readUDP(const int readSize); //Read via UDP protocol (Only for blocking socket)
void writeUDP(string message);      //Write via UDP protocol (Only for blocking socket)
};

我已将 UDP.cpp 更新为:

#include "udp.hpp"
UDP::UDP()
{
}
UDP::~UDP()
{
closeSocket();
}
void UDP::initNonBlock()
{
if ((fdSocketUDP_ = socket(AF_INET, SOCK_DGRAM, 0)) < 0) //Create UDP socket
{
perror("Error - socket creation - udp.cpp");
exit(EXIT_FAILURE);
}
fcntl(fdSocketUDP_, F_SETFL, O_NONBLOCK); //Set to non-blocking mode 
memset(&ServerAddress_, 0, sizeof(ServerAddress_)); //Sets ServerAddress_ to 0
memset(&ClientAddress_, 0, sizeof(ClientAddress_)); //Sets ClientAddress_ to 0
ServerAddress_.sin_family = AF_INET;         //Address family, must be AF_INET = IPv4
ServerAddress_.sin_port = htons(c_PORT);     //PORT number, convert PORT number to network byte order using htons()
ServerAddress_.sin_addr.s_addr = INADDR_ANY; //IP-Address of host (server IP), INADDR_ANY gets this IP Address
if (bind(fdSocketUDP_, (const struct sockaddr *)&ServerAddress_, sizeof(ServerAddress_)) < 0) //Bind the socket to ServerAddress_
{
perror("Error - socket bind - udp.cpp");
exit(EXIT_FAILURE);
}
}
void UDP::initBlock()
{
if ((fdSocketUDP_ = socket(AF_INET, SOCK_DGRAM, 0)) < 0) //Create UDP socket
{
perror("Error - socket creation - udp.cpp");
exit(EXIT_FAILURE);
}
memset(&ServerAddress_, 0, sizeof(ServerAddress_)); //Sets ServerAddress_ to 0
memset(&ClientAddress_, 0, sizeof(ClientAddress_)); //Sets ClientAddress_ to 0
ServerAddress_.sin_family = AF_INET;         //Address family, must be AF_INET = IPv4
ServerAddress_.sin_port = htons(c_PORT);     //PORT number, convert PORT number to network byte order using htons()
ServerAddress_.sin_addr.s_addr = INADDR_ANY; //IP-Address of host (server IP), INADDR_ANY gets this IP Address
if (bind(fdSocketUDP_, (const struct sockaddr *)&ServerAddress_, sizeof(ServerAddress_)) < 0) //Bind the socket to ServerAddress_
{
perror("Error - socket bind - udp.cpp");
exit(EXIT_FAILURE);
}
}
void UDP::closeSocket()
{
close(fdSocketUDP_); //Close socket
}
string UDP::readNonBlock(const int readSize)
{
char readMsg[readSize] = {0}; //Read buffer
ClientAddressLength_ = sizeof(ClientAddress_);
recvfrom(fdSocketUDP_, readMsg, readSize, 0, (struct sockaddr *)&ClientAddress_, (socklen_t *)&ClientAddressLength_);
string str(readMsg);           //Convert char array to string
str = str.substr(0, readSize); //Make sure the string is the length of readsize
return str;
}                    
string UDP::readUDP(const int readSize)
{
char readMsg[readSize] = {0}; //Read buffer
ClientAddressLength_ = sizeof(ClientAddress_);
if ((recvfrom(fdSocketUDP_, readMsg, readSize, 0, (struct sockaddr *)&ClientAddress_, (socklen_t *)&ClientAddressLength_)) < 0) //Receive data via UDP protocol
{
perror("Error - recvfrom - udp.cpp");
exit(EXIT_FAILURE);
}
string str(readMsg);           //Convert char array to string
str = str.substr(0, readSize); //Make sure the string is the length of readsize
return str;
}
void UDP::writeUDP(string message)
{
//Make char array 
int writeSize = message.size();
char writeMsg[writeSize + 1] = {''};
//Convert string message to char array
for (int i = 0; i < writeSize; i++)
{
writeMsg[i] = message[i];
}
if ((sendto(fdSocketUDP_, writeMsg, writeSize, 0, (const struct sockaddr *)&ClientAddress_, (socklen_t)ClientAddressLength_)) < 0) //Send data via UDP protocol
{
perror("Error - sendto - udp.cpp");
exit(EXIT_FAILURE);
}
}

多亏了这一点,我才能够打破 do-while 循环:

udp.closeSocket();
udp.initNonBlock();
do
{
//Do something 
} while (udp.readNonBlock(3).compare("153") != 0);
udp.closeSocket();
udp.initBlock();

如果从 UDP 客户端发送的消息是"153",则会中断 do-while 循环。