C++ 在 Qt 中的行为不同,bind() returns EINVAL
C++ behaves differently in Qt, bind() returns 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, 0, sizeof(struct sockaddr_un));
memset(&send_addr, 0, 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()
总是 return 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, 0, sizeof (send_address));
memset(&recv_address, 0, 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, SOCK_DGRAM, 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, offsetof(struct sockaddr_un, 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 无法识别 class.可能是因为我在使用 Qt 6.x 并且它现在已被弃用(尽管我没有发现任何官方弃用通知)。我该怎么办?我做错了什么?
strncpy
将从源到目标最多复制 n
个字节。如果 n 字节内没有 null char,则不会复制它。 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,
wpa_send_ctrl_iface.toStdString().c_str(),
sizeof(send_address.sun_path) );
strncpy(recv_address.sun_path,
wpa_recv_ctrl_iface.toStdString().c_str(),
sizeof(recv_address.sun_path));
此外,正如评论中所讨论的,bind
的长度参数看起来也很时髦。尝试进行上述更改。
绝对与 Qt 无关:您对 sockaddr 结构的全 0 执行 memset
在 之后,您已将套接字的系列设置为 AF_UNIX
(在大多数平台上为“1”)。系统应该如何知道您需要本地套接字?
我已经检查过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, 0, sizeof(struct sockaddr_un));
memset(&send_addr, 0, 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()
总是 return 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, 0, sizeof (send_address));
memset(&recv_address, 0, 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, SOCK_DGRAM, 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, offsetof(struct sockaddr_un, 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 无法识别 class.可能是因为我在使用 Qt 6.x 并且它现在已被弃用(尽管我没有发现任何官方弃用通知)。我该怎么办?我做错了什么?
strncpy
将从源到目标最多复制 n
个字节。如果 n 字节内没有 null char,则不会复制它。 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,
wpa_send_ctrl_iface.toStdString().c_str(),
sizeof(send_address.sun_path) );
strncpy(recv_address.sun_path,
wpa_recv_ctrl_iface.toStdString().c_str(),
sizeof(recv_address.sun_path));
此外,正如评论中所讨论的,bind
的长度参数看起来也很时髦。尝试进行上述更改。
绝对与 Qt 无关:您对 sockaddr 结构的全 0 执行 memset
在 之后,您已将套接字的系列设置为 AF_UNIX
(在大多数平台上为“1”)。系统应该如何知道您需要本地套接字?