#include < iostream > #include < boost / array.hpp > #include < boost / asio.hpp > // 本程序的目的是访问一个时间同步服务器,我们需要用户指定一个服务器(如time-a.nist.gov),用IP亦可. using boost::asio::ip::tcp; int main( int argc, char * argv[]) ... { try ...{ if (argc != 2) ...{ std::cerr << "Usage: client <host>" << std::endl; return 1; } //用asio进行网络连接至少需要一个boost::asio::io_service对象 boost::asio::io_service io_service; /**//* 我们需要把在命令行参数中指定的服务器转换为TCP上的节点. 完成这项工作需要boost::asio::ip::tcp::resolver对象 */ tcp::resolver resolver(io_service); /**//* 一个resolver对象查询一个参数,并将其转换为TCP上节点的列表. 这里我们把argv[1]中的sever的名字和要查询字串daytime关联. */ tcp::resolver::query query(argv[1], "daytime"); /**//* 节点列表可以用 boost::asio::ip::tcp::resolver::iterator 来进行迭代. iterator默认的构造函数生成一个end iterator. */ tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); tcp::resolver::iterator end; /**//* 现在我们建立一个连接的sockert,由于获得节点既有IPv4也有IPv6的. 所以,我们需要依次尝试他们直到找到一个可以正常工作的.这步使得我们的程序独立于IP版本 */ tcp::socket socket(io_service); boost::asio::error error = boost::asio::error::host_not_found; while (error && endpoint_iterator != end) ...{ socket.close(); socket.connect(*endpoint_iterator++, boost::asio::assign_error(error)); } if (error) throw error; /**//* 连接完成,我们需要做的是读取daytime服务器的响应. 我们用boost::array来保存得到的数据,boost::asio::buffer()会自动根据array的大小暂停工作, 来防止缓冲溢出.除了使用boost::array,也可以使用char [] 或std::vector. */ for (;;) ...{ boost::array<char, 128> buf; boost::asio::error error; size_t len = socket.read_some( boost::asio::buffer(buf), boost::asio::assign_error(error)); /**//* 当服务器关闭连接时,boost::asio::ip::tcp::socket::read_some()会用boost::asio::error::eof标志完成, 这时我们应该退出读取循环了. */ if (error == boost::asio::error::eof) break; // Connection closed cleanly by peer. else if (error) throw error; // Some other error. std::cout.write(buf.data(), len); } } catch (std::exception& e) ...{ std::cerr << e.what() << std::endl; }}
注:下面这一段如果看起来有点麻烦的话可以写简单些,就让其只解析ipv4类型地址,端口号为13,只连接一次
tcp::resolver::query query(argv[ 1 ], " daytime " ); tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); tcp::resolver::iterator end; tcp::socket socket(io_service); boost::asio::error error = boost::asio::error::host_not_found; while (error && endpoint_iterator != end) ... { socket.close(); socket.connect(*endpoint_iterator, boost::asio::assign_error(error)); } if (error) throw error;
简单点的:
// 域名解析,只将域名解析为ipv4地址 tcp::resolver::query query(tcp::v4(),argv[ 1 ], " 13 " ); tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); // 只连接一次 tcp::socket socket(io_service); boost::asio::error error = boost::asio::error::host_not_found; socket.connect( * endpoint_iterator , boost::asio::assign_error(error)); if (error) throw error;
下面是用winsock api(阻塞模式) 所写的代码,可以比较一下
#include < iostream > #include < winsock2.h > #pragma comment(lib,"ws2_32.lib") int main( int argc, char * argv[]){ if (argc < 2 ) { std::cout << " usage: tcp_datatime hostname(time-a.nist.gov) " << std::endl; return - 1 ; } WSADATA wsaData; if (WSAStartup(MAKEWORD( 2 , 2 ), & wsaData) != 0 ) { std::cout << " lib error " ; return - 1 ; } SOCKET cliSocket; cliSocket = socket(AF_INET, SOCK_STREAM, 0 ); SOCKADDR_IN addr; memset( & addr, 0 , sizeof (addr)); addr.sin_port = htons( 13 ); addr.sin_family = AF_INET; if ( (addr.sin_addr.s_addr = inet_addr(argv[ 1 ])) == INADDR_NONE) { hostent * hostent; hostent = gethostbyname(argv[ 1 ]); if (hostent == NULL) { std::cout << " can't resolve host! " ; return - 1 ; } memcpy( & addr.sin_addr,hostent -> h_addr_list[ 0 ], 4 ); } if ( connect(cliSocket, (sockaddr * ) & addr, sizeof (sockaddr)) != 0 ) { std::cout << " connect error " ; return - 1 ; } char buf[ 100 ]; int recvSize = recv(cliSocket, buf, sizeof (buf), 0 ); buf[recvSize] = 0 ; std::cout << buf << std::endl; return 0 ;}