SCTP recvmsg returns EFAULT(错误地址)
SCTP recvmsg returns EFAULT (Bad Address)
我正在尝试构建一个非常简单和基本的 STCP 一对多服务器用于测试目的,但由于某种原因,套接字似乎只能接收一条消息。收到一条消息后,随后每次调用 recvmsg
returns -1,errno
为 EFAULT
。这对我来说完全没有意义,所以也许你可以告诉我我在这里没有看到的东西。 EFAULT
应该在
时返回
EFAULT
The receive buffer pointer(s) point outside the process's address space.
绝对不是这样。
#include <ctype.h>
#include <cstring>
#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main(int argc, char** argv) {
struct sockaddr_in bind_address;
bind_address.sin_family = AF_INET;
bind_address.sin_port = htons(51338);
bind_address.sin_addr.s_addr = INADDR_ANY;
int sock = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
if (sock == -1) {
perror("Error while creating socket");
return 1;
}
int rv = bind(sock, (struct sockaddr*)(&bind_address), sizeof(bind_address));
if (rv != 0 ) {
perror("Error while binding socket");
return 1;
}
rv = listen(sock, 1);
if (rv != 0 ) {
perror("Error while listening");
return 1;
}
struct iovec iov[1];
iov[0].iov_base = malloc(1500);
iov[0].iov_len = 1500;
struct sockaddr_in sin = {};
char control[1000] = { 0 };
struct msghdr mhdr;
mhdr.msg_iov = iov;
mhdr.msg_iovlen = sizeof(iov);
mhdr.msg_name = &sin;
mhdr.msg_namelen = sizeof(sin);
mhdr.msg_control = &control;
mhdr.msg_controllen = sizeof(control);
while (true) {
std::memset(iov[0].iov_base, 0, iov[0].iov_len);
std::memset(&sin, 0, sizeof(sin));
int recv_bytes = recvmsg(sock, &mhdr, 0);
if (recv_bytes == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
continue;
} else {
perror("Err");
}
break;
}
std::cout << "Received message: " << std::endl;
std::cout << (char*)iov[0].iov_base << std::endl;
}
return 0;
}
这个错误很可能是因为第一次调用recvmsg()
覆盖了堆栈上的一些数据,导致mhdr
里面的一个指针无效。这可能是因为这一行:
mhdr.msg_iovlen = sizeof(iov);
这不应包含数组 iov
的大小(以字节为单位),而应仅包含该数组中元素的数量,因此:
mhdr.msg_iovlen = sizeof(iov) / sizeof(*iov); // which equals 1 in this case
我正在尝试构建一个非常简单和基本的 STCP 一对多服务器用于测试目的,但由于某种原因,套接字似乎只能接收一条消息。收到一条消息后,随后每次调用 recvmsg
returns -1,errno
为 EFAULT
。这对我来说完全没有意义,所以也许你可以告诉我我在这里没有看到的东西。 EFAULT
应该在
EFAULT
The receive buffer pointer(s) point outside the process's address space.
绝对不是这样。
#include <ctype.h>
#include <cstring>
#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main(int argc, char** argv) {
struct sockaddr_in bind_address;
bind_address.sin_family = AF_INET;
bind_address.sin_port = htons(51338);
bind_address.sin_addr.s_addr = INADDR_ANY;
int sock = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
if (sock == -1) {
perror("Error while creating socket");
return 1;
}
int rv = bind(sock, (struct sockaddr*)(&bind_address), sizeof(bind_address));
if (rv != 0 ) {
perror("Error while binding socket");
return 1;
}
rv = listen(sock, 1);
if (rv != 0 ) {
perror("Error while listening");
return 1;
}
struct iovec iov[1];
iov[0].iov_base = malloc(1500);
iov[0].iov_len = 1500;
struct sockaddr_in sin = {};
char control[1000] = { 0 };
struct msghdr mhdr;
mhdr.msg_iov = iov;
mhdr.msg_iovlen = sizeof(iov);
mhdr.msg_name = &sin;
mhdr.msg_namelen = sizeof(sin);
mhdr.msg_control = &control;
mhdr.msg_controllen = sizeof(control);
while (true) {
std::memset(iov[0].iov_base, 0, iov[0].iov_len);
std::memset(&sin, 0, sizeof(sin));
int recv_bytes = recvmsg(sock, &mhdr, 0);
if (recv_bytes == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
continue;
} else {
perror("Err");
}
break;
}
std::cout << "Received message: " << std::endl;
std::cout << (char*)iov[0].iov_base << std::endl;
}
return 0;
}
这个错误很可能是因为第一次调用recvmsg()
覆盖了堆栈上的一些数据,导致mhdr
里面的一个指针无效。这可能是因为这一行:
mhdr.msg_iovlen = sizeof(iov);
这不应包含数组 iov
的大小(以字节为单位),而应仅包含该数组中元素的数量,因此:
mhdr.msg_iovlen = sizeof(iov) / sizeof(*iov); // which equals 1 in this case