我先从boost::asio库的一个范例程序,开始学习asio库.
#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;
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;
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 ;
}
#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 ;
}