socket() 在 std::thread 内返回文件描述符 1
socket() returning file descriptor 1 inside std::thread
当我在 std::thread()
中调用 socket()
时,它 returns 的套接字描述符为 1。调用 std::cout
而不是将用于终端的文本发送到服务器.当我在调用 socket()
之前添加 cout << "";
时,会创建 stdin/out/err 和 socket()
returns 3.
的描述符
来自 http://www.cplusplus.com/reference/iostream/cout/:
In terms of static initialization order, cout
is guaranteed to be properly constructed and initialized no later than the first time an object of type ios_base::Init
is constructed, with the inclusion of <iostream>
counting as at least one initialization of such objects with static duration.
By default, cout
is synchronized with stdout
(see ios_base::sync_with_stdio
).
std::cout
应该已经初始化并同步到标准输出,这解释了为什么 std::cout
将消息发送到服务器而不是终端。
我想知道调用 std::thread()
是否会关闭新线程中的 stdin/out/err 描述符,或者这些描述符是否不存在于线程中,因为线程不是由终端创建的,或者初始化?
我 运行 在 RHEL 6.4 上使用 GCC 4.8.2。为了完整起见,我在下面包含了我的客户端代码,并注释掉了额外的 cout << "";
。
Client.cpp:
#include "Client.hpp"
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <thread>
#include <vector>
#include <algorithm>
#include <sstream>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
using namespace std;
Client::Client( const string& hostname, const string& port ) {
this->hostname = hostname;
this->port = port;
}
Client::~Client() { close( fd ); }
void Client::operator()() {
struct addrinfo hints;
memset( &hints, 0, sizeof( struct addrinfo ) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = 0;
struct addrinfo *result;
int ret = getaddrinfo( hostname.c_str(), port.c_str(), &hints, &result );
if( ret != 0) {
cerr << "getaddrinfo failed: " << gai_strerror( ret ) << endl;
return;
}
// cout << ""; // prevents socket() from returning 1 and redefining cout
struct addrinfo *rp = NULL;
for( rp = result; rp != NULL; rp = rp->ai_next ) {
fd = socket( rp->ai_family, rp->ai_socktype, rp->ai_protocol );
if( fd == -1 ) {
continue; /* Error */
}
if( connect( fd, rp->ai_addr, rp->ai_addrlen ) != -1) {
break; /* Success */
}
close( fd ); /* Try again */
}
if( rp == NULL ) {
cerr << "Failed to connect to " << hostname << ":" << port << endl;
return;
}
freeaddrinfo( result );
cout << "Starting echo client" << endl;
int i = 0;
do {
stringstream ss;
ss << "Thread " << this_thread::get_id() << ": Message #" << ++i;
string str = ss.str();
_send( str.c_str() );
string msg = _recv();
//cout << "Thread " << this_thread::get_id() << " received message: " << msg << endl;
} while ( i < 10 );
cout << "Stopping echo client" << endl;
close( fd );
}
string Client::_recv( ) const {
const int BUF_SIZE = 1024;
char* buf = ( char * ) malloc( sizeof( char) * BUF_SIZE );
memset( buf, '[=11=]', sizeof( char ) * BUF_SIZE );
int bytes = recv( fd, buf, BUF_SIZE, 0 );
if( bytes < 0 ) {
perror( "recv failed" );
}
string msg = string( buf );
free( buf );
return msg;
}
void Client::_send( const string buf ) const {
if( send( fd, buf.c_str(), buf.length(), 0 ) < 0 ) {
perror( "send failed" );
}
}
void usage() {
cerr << "Usage: client <hostname> <port>" << endl;
cerr << " hostname - server name listening for incoming connctions" << endl;
cerr << " port - internet port to listen for connections from" << endl;
}
int main( int argc, char* argv[] ) {
if( argc < 3 ) {
cerr << "Not enough arguments!" << endl;
usage();
return EXIT_FAILURE;
}
vector<thread> clients;
for( int i = 0; i < 1; i++ ) {
clients.push_back( thread( ( Client( argv[1], argv[2] ) ) ) );
}
for_each( clients.begin(), clients.end(), mem_fn( &thread::join ) );
return EXIT_SUCCESS;
}
Client.hpp:
#ifndef __CLIENT_HPP__
#define __CLIENT_HPP__
#include <string>
class Client {
private:
int fd;
std::string hostname;
std::string port;
std::string _recv( ) const;
void _send( const std::string buf ) const;
public:
Client( const std::string& hostname, const std::string& port);
~Client();
void operator()();
};
#endif
如果您不小心关闭了 stdout
,通常会发生这种情况,即存在虚假的 close(1);
。然后 FD 将合法地成为 1 号。这很可能在程序的其他地方。
我遇到过几次,通常用 gdb
找到它并在 close()
上设置断点。
你的析构函数看起来很可疑:
Client::~Client() { close( fd ); }
你不应该在构造函数中将 fd
设置为 -1
,并在你关闭它的任何其他地方小心地将 fd
设置为 -1
,而不是这样做如果 fd==-1
关闭?当前创建一个 Client
并销毁它会关闭一个随机 fd。
当我在 std::thread()
中调用 socket()
时,它 returns 的套接字描述符为 1。调用 std::cout
而不是将用于终端的文本发送到服务器.当我在调用 socket()
之前添加 cout << "";
时,会创建 stdin/out/err 和 socket()
returns 3.
来自 http://www.cplusplus.com/reference/iostream/cout/:
In terms of static initialization order,
cout
is guaranteed to be properly constructed and initialized no later than the first time an object of typeios_base::Init
is constructed, with the inclusion of<iostream>
counting as at least one initialization of such objects with static duration.By default,
cout
is synchronized withstdout
(seeios_base::sync_with_stdio
).
std::cout
应该已经初始化并同步到标准输出,这解释了为什么 std::cout
将消息发送到服务器而不是终端。
我想知道调用 std::thread()
是否会关闭新线程中的 stdin/out/err 描述符,或者这些描述符是否不存在于线程中,因为线程不是由终端创建的,或者初始化?
我 运行 在 RHEL 6.4 上使用 GCC 4.8.2。为了完整起见,我在下面包含了我的客户端代码,并注释掉了额外的 cout << "";
。
Client.cpp:
#include "Client.hpp"
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <thread>
#include <vector>
#include <algorithm>
#include <sstream>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
using namespace std;
Client::Client( const string& hostname, const string& port ) {
this->hostname = hostname;
this->port = port;
}
Client::~Client() { close( fd ); }
void Client::operator()() {
struct addrinfo hints;
memset( &hints, 0, sizeof( struct addrinfo ) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = 0;
struct addrinfo *result;
int ret = getaddrinfo( hostname.c_str(), port.c_str(), &hints, &result );
if( ret != 0) {
cerr << "getaddrinfo failed: " << gai_strerror( ret ) << endl;
return;
}
// cout << ""; // prevents socket() from returning 1 and redefining cout
struct addrinfo *rp = NULL;
for( rp = result; rp != NULL; rp = rp->ai_next ) {
fd = socket( rp->ai_family, rp->ai_socktype, rp->ai_protocol );
if( fd == -1 ) {
continue; /* Error */
}
if( connect( fd, rp->ai_addr, rp->ai_addrlen ) != -1) {
break; /* Success */
}
close( fd ); /* Try again */
}
if( rp == NULL ) {
cerr << "Failed to connect to " << hostname << ":" << port << endl;
return;
}
freeaddrinfo( result );
cout << "Starting echo client" << endl;
int i = 0;
do {
stringstream ss;
ss << "Thread " << this_thread::get_id() << ": Message #" << ++i;
string str = ss.str();
_send( str.c_str() );
string msg = _recv();
//cout << "Thread " << this_thread::get_id() << " received message: " << msg << endl;
} while ( i < 10 );
cout << "Stopping echo client" << endl;
close( fd );
}
string Client::_recv( ) const {
const int BUF_SIZE = 1024;
char* buf = ( char * ) malloc( sizeof( char) * BUF_SIZE );
memset( buf, '[=11=]', sizeof( char ) * BUF_SIZE );
int bytes = recv( fd, buf, BUF_SIZE, 0 );
if( bytes < 0 ) {
perror( "recv failed" );
}
string msg = string( buf );
free( buf );
return msg;
}
void Client::_send( const string buf ) const {
if( send( fd, buf.c_str(), buf.length(), 0 ) < 0 ) {
perror( "send failed" );
}
}
void usage() {
cerr << "Usage: client <hostname> <port>" << endl;
cerr << " hostname - server name listening for incoming connctions" << endl;
cerr << " port - internet port to listen for connections from" << endl;
}
int main( int argc, char* argv[] ) {
if( argc < 3 ) {
cerr << "Not enough arguments!" << endl;
usage();
return EXIT_FAILURE;
}
vector<thread> clients;
for( int i = 0; i < 1; i++ ) {
clients.push_back( thread( ( Client( argv[1], argv[2] ) ) ) );
}
for_each( clients.begin(), clients.end(), mem_fn( &thread::join ) );
return EXIT_SUCCESS;
}
Client.hpp:
#ifndef __CLIENT_HPP__
#define __CLIENT_HPP__
#include <string>
class Client {
private:
int fd;
std::string hostname;
std::string port;
std::string _recv( ) const;
void _send( const std::string buf ) const;
public:
Client( const std::string& hostname, const std::string& port);
~Client();
void operator()();
};
#endif
如果您不小心关闭了 stdout
,通常会发生这种情况,即存在虚假的 close(1);
。然后 FD 将合法地成为 1 号。这很可能在程序的其他地方。
我遇到过几次,通常用 gdb
找到它并在 close()
上设置断点。
你的析构函数看起来很可疑:
Client::~Client() { close( fd ); }
你不应该在构造函数中将 fd
设置为 -1
,并在你关闭它的任何其他地方小心地将 fd
设置为 -1
,而不是这样做如果 fd==-1
关闭?当前创建一个 Client
并销毁它会关闭一个随机 fd。