避免在 C/C++ 和 std::array 中使用 TCP 时阻止程序

Avoid blocking the program while using TCP in C/C++ and std::array

本文关键字:TCP 程序 array C++ std      更新时间:2023-10-16

我正在使用Ubuntu,我有一个C/C++应用程序,它使用WxWidgets并通过TCP发送字符串。 只有当路由器和连接正常时,它才能正常工作,否则它会卡住,我需要手动退出应用程序。

我以这种方式调用该函数:

SendCommand ptr;
if ( ptr.sendcommand(16,16,1) ){
printf("Porta Apertan");
} else {
printf("Errore di comunicazione - porta non apertan");
}

这是函数:

int SendCommand::sendcommand(int relay_on, int relay_off, int stop){
printf("eseguo la funzione nella classen");
std::array<uint8_t, 8> command1;
std::array<uint8_t, 8> command2;
switch(relay_on){
case 16: command1 = {0x58, 0x01, 0x12, 0x00, 0x00, 0x00, 0x10, 0x7B}; // switch on the relay 16
break;
}
switch(relay_off){
case 16: command2 = {0x58, 0x01, 0x11, 0x00, 0x00, 0x00, 0x10, 0x7A}; // switch off the relay 16
break;
}
int sockfd, n;
struct sockaddr_in servaddr;
std::string serveraddr = "192.168.1.4";
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if ( sockfd < 0 )
{
cerr << "Error creating socket! " << strerror(errno) << endl;
return -1;
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(serveraddr.c_str());
servaddr.sin_port = htons(3000);
if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
{
cerr << "Error connecting socket!" << strerror(errno) << endl;
close(sockfd);
return -1;
}
//Relay #14 per porta bilancia
printf("Apro la portan");
int bytes_to_send1 = sizeof(command1);
int bytes_to_send2 = sizeof(command2);
int bytes_sent1 = 0;
int bytes_sent2 = 0;
do
{
n = send(sockfd, command1.data() + bytes_sent1, bytes_to_send1 - bytes_sent1, 0);
if ( n < 0 )
{
cerr << "Error writing to socket!" << strerror(errno) << endl;
close(sockfd);
}
bytes_sent1 += n;
}
while (bytes_sent1 < bytes_to_send1);
n=0;
sleep(stop);
do
{
n = send(sockfd, command2.data() + bytes_sent2, bytes_to_send2 - bytes_sent2, 0);
if ( n < 0 )
{
cerr << "Error writing to socket!" << strerror(errno) << endl;
close(sockfd);
}
bytes_sent2 += n;
}
while (bytes_sent2 < bytes_to_send2);
close(sockfd);
n=0;

return 1;
}

由于在上一个主题中收到的建议,我正在使用符号std::array<uint8_t, 8> command1;来定义要通过网络发送的内容的数组,但是即使网络上出现问题,我也找不到让程序正确流动的解决方案。 我尝试使用线程或 fork() 并且它可以工作,但是还有其他更简单的解决方案吗?

附言当它因为没有互联网连接而卡住时,它会在这里阻止:

if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
{
cerr << "Error connecting socket!" << strerror(errno) << endl;
close(sockfd);
return -1;
}

它永远不会进入 if 条件。

几个选项

  1. 使用提升 ASIO
  2. 线程/进程
  3. 将超时设置为低(例如,g - 5 秒),因此阻止相对较少的时间
  4. 设置套接字非阻塞并在其上进行 epoll(涉及线程)。

对于 2 - 尝试使用 std 线程,应该易于使用(您也可以选择异步 + lambda 并使用期货简化控制流)。

这样代码看起来会更容易阅读。

对于 3 和 4 - 您需要设置套接字非阻塞并进行轮询(通过 select 或 epoll) - 请参阅 fnctl(.., O_NONBLOCK ..) select()。如果您没有收到错误,那么您可以按原样使用套接字(或者可能从异步返回它并在将来获取)。