微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C++ 在 Qt 中的行为不同,bind() 返回 EINVAL

如何解决C++ 在 Qt 中的行为不同,bind() 返回 EINVAL

我已经检查了 bind() return EINVAL 并且这不是这里的问题。请在对重复内容感到愤怒之前通读一遍。

我正在尝试连接到 wpa_supplicant。基本上我正在尝试使用 C++ 来实现这一点:

import os
import select
import socket

interface = "wlp4s0"
wpa_send_path = "/run/wpa_supplicant/"+interface
wpa_recv_path = "/tmp/wpa_ctrl_{pid}-{count}".format(pid=os.getpid(),count=1)

soc = socket.socket(socket.AF_UNIX,socket.soCK_DGRAM,0)
soc.bind(wpa_recv_path)
soc.connect(wpa_send_path)

print("> PING")
soc.send(b"PING")
print("<",soc.recv(4096).decode().strip())

来自https://gist.github.com/artizirk/cd3980c8ff870eb0bfce68bc26a2676b

而且我已经完成了我想做的事情,但使用的是普通的 C++。这是代码

#include <iostream>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <sys/un.h>

#define PATH   "/run/wpa_supplicant/wlp4s0"
char path[100] = "/tmp/wpa_ctrl_";

int main(void) {

  int ctrl_socket;
  char buffer[1024];
  struct sockaddr_un socket_addr,send_addr;

  memset(&socket_addr,sizeof(struct sockaddr_un));
  memset(&send_addr,sizeof(struct sockaddr_un));

  socket_addr.sun_family = AF_UNIX;
  send_addr.sun_family = AF_UNIX;

  strcpy(send_addr.sun_path,PATH);

  strcat(path,std::to_string(getpid()).c_str());
  strcat(path,"-1");
  strcat(socket_addr.sun_path,path);

  if ((ctrl_socket = socket(AF_UNIX,SOCK_DGRAM,0)) == -1) {
    std::cerr << "Error creating socket!" << std::endl;
    std::exit(EXIT_FAILURE);
  }

  /* Unlink if already bound */
  unlink(socket_addr.sun_path);

  if ((connect(ctrl_socket,(struct sockaddr *)&send_addr,SUN_LEN(&send_addr))) == -1) {
    std::cerr << "Error connecting to socket!" << std::endl;
    std::exit(EXIT_FAILURE);
  }

  if (bind(ctrl_socket,(const struct sockaddr *)&socket_addr,offsetof(struct sockaddr_un,sun_path) + strlen(path) + 1) == -1) {
        perror("Error");
        exit(EXIT_FAILURE);
  }

  send(ctrl_socket,"PING",5,0);
  recv(ctrl_socket,buffer,1024,0);

  std::cout << buffer << std::endl;

  close(ctrl_socket);

  return 0;
}

这段代码工作正常。但是当我在 Qt 中这样做时,bind() 总是返回 EINVAL,即 Invalid Arguments。这是代码

WPASupplicantControl::WPASupplicantControl(std::string wlan_interface_name)
    :wpa_send_ctrl_iface(WPA_SEND_CTRL_IFACE_PREFIX + QString::fromStdString(wlan_interface_name)),wpa_recv_ctrl_iface(
          WPA_RECV_CTRL_IFACE_PREFIX +
          QString::fromStdString(std::to_string(getpid())) +
          "-1"
          )
{
    struct sockaddr_un send_address,recv_address;

    send_address.sun_family = AF_UNIX;
    recv_address.sun_family = AF_UNIX;

    memset(&send_address,sizeof (send_address));
    memset(&recv_address,sizeof (recv_address));

    strncpy(send_address.sun_path,wpa_send_ctrl_iface.toStdString().c_str(),wpa_send_ctrl_iface.length());
    strncpy(recv_address.sun_path,wpa_recv_ctrl_iface.toStdString().c_str(),wpa_send_ctrl_iface.length());

    if ((wpa_control_socket = socket(AF_UNIX,0)) == -1) {
        qCritical() << "socket() Failed!";
        exit(EXIT_FAILURE);
    }

    /* Attatch to sending and receiving control interfaces */
    if (connect(wpa_control_socket,(const struct sockaddr *)&send_address,SUN_LEN(&send_address)) == -1) {
        qCritical() << "Error connecting to wpa_supplicant send control iface!";
        close(wpa_control_socket);
        exit(EXIT_FAILURE);
    }

    /* Detatch if it's already bound */
    unlink(recv_address.sun_path);

    if (bind(wpa_control_socket,(const struct sockaddr *)&recv_address,sun_path) + wpa_recv_ctrl_iface.length() + 1) == -1) {
        qCritical() << "Error binding to wpa_supplicant recv control iface!";
        close(wpa_control_socket);
        exit(EXIT_FAILURE);
    }
}

测试此代码功能性虚拟项目位于:https://github.com/gaurav712/socket_test

我已经检查了数百次所有值,它们都很好,但仍然无法正常工作。它就在那个 connect() 调用上。

我想我应该使用特定于 Qt 的东西,我发现了 QLocalSocket https://doc.qt.io/qt-5/qlocalsocket.html 但是当我导入它时,Qt 无法识别该类。可能是因为我使用的是 Qt 6.x 并且它现在已被弃用(尽管我没有找到任何官方弃用通知)。我该怎么办?我做错了什么?

解决方法

与 Qt 完全无关:您对所有 sockaddr 结构执行 memset 之后您将套接字的系列设置为 AF_UNIX(这是大多数平台上的“1”)。系统如何知道您需要本地套接字?

,

strncpy 将最多 n 个字节从源复制到目标。如果 n 个字节内没有空字符,则不会复制它。 strncpy 的第三个参数通常用于传达目标缓冲区的长度。

改变这个:

strncpy(send_address.sun_path,wpa_send_ctrl_iface.toStdString().c_str(),wpa_send_ctrl_iface.length());
strncpy(recv_address.sun_path,wpa_recv_ctrl_iface.toStdString().c_str(),wpa_send_ctrl_iface.length());

成为这样:

strncpy(send_address.sun_path,sizeof(send_address.sun_path) );

strncpy(recv_address.sun_path,sizeof(recv_address.sun_path));

此外,正如评论中所讨论的,您对 bind 的长度参数也看起来很时髦。尝试以上更改。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。