[英]Got “Bad file descriptor” when use boost::asio and boost::thread
[英]“Bad file descriptor” when accessing socket descriptor in child thread
當嘗試在子線程中訪問套接字描述符(使用bind()或listen())時,出現錯誤:
錯誤的文件描述符
這是代碼(標題被忽略):
class task {
private:
std::int32_t socFd;
std::string path;
char buffer[MAX_SOC_BUFFER];
struct sockaddr_un socAddr;
public:
void init() {
if ((socFd = socket((std::int32_t)AF_UNIX, (std::int32_t)SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
socAddr.sun_family = AF_UNIX;
strcpy(socAddr.sun_path, getSocPath().c_str());
}
task(const std::string& path) : path{path}
{
init();
}
auto getSocketFd() ->decltype(socFd) {
return socFd;
}
const std::string& getSocPath() {
return path;
}
auto getSocAddr() -> decltype(socAddr)&
{
return socAddr;
}
char* getBuff() {
return buffer;
}
virtual ~ task() {
close(getSocketFd());
}
};
class server_task : public task{
public:
void init () {
::unlink(getSocPath().c_str());
size_t len = sizeof(getSocAddr());
if (bind(getSocketFd(), (struct sockaddr *)&(getSocAddr()), len) == -1) {
perror("bind");
exit(1);
}
}
server_task(const std::string& path) : task(path)
{
init();
}
void operator()() {
struct sockaddr_un remote;
if (listen(getSocketFd(), 5) == -1) {
perror("listen");
exit(1);
}
for(;;) {
int done, n, socFd2;
printf("Waiting for a connection...\n");
socklen_t t = sizeof(remote);
if ((socFd2 = accept(getSocketFd(), (struct sockaddr *)&remote, &t)) == -1) {
perror("accept");
exit(1);
}
printf("Connected.\n");
done = 0;
do {
n = recv(socFd2, getBuff(), 100, 0);
if (n <= 0) {
if (n < 0) perror("recv");
done = 1;
}
if (!done) {
std::string buffStr(getBuff());
std::transform(buffStr.begin(), buffStr.end(),buffStr.begin(), ::toupper);
if (send(socFd2, buffStr.c_str(), n, 0) < 0) {
perror("send");
done = 1;
}
}
} while (!done);
close(socFd2);
}
}
};
int main(){
std::vector<std::thread> threads;
server_task server("/tmp/temp_socket");
threads.push_back(std::thread(server));
for(auto& thread : threads)
thread.join();
return 0;
}
如果我將main()
函數更改為:
int main(){
server_task server("/tmp/temp_socket");
server();
return 0;
}
不會發生此類錯誤。 據我了解,文件描述符表在父進程及其子線程之間共享,因此套接字句柄應該有效。
我究竟做錯了什么?
threads.push_back(std::thread(server));
這將創建server
對象的至少一個副本,可能是多個副本,並且由於尚未定義副本構造函數,因此每個副本都共享相同的套接字,而第一個超出范圍的副本將關閉套接字。 到新線程啟動時,臨時副本已被銷毀並關閉了套接字,因此在新線程中運行的server_task
的副本指的是已關閉的套接字。
您應該為您的task
和server_task
類型定義一個移動構造函數,以便不復制套接字的所有權,然后將該對象移動到線程中:
thread.push_back(std::thread(std::move(server)));
否則,您應該通過引用將服務器傳遞給新線程,以便沒有副本:
thread.push_back(std::thread(std::ref(server)));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.