ASIO—下一代C++标准可能接纳的网络库(2)TCP网络应用

               

ASIO—下一代C++标准可能接纳的网络库(2TCP网络应用

write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie

讨论新闻组及文件

一、   综述

本文仅仅是附着在boost::asio文档的一个简单说明和讲解,没有boost::asio文档可能你甚至都不知道我在讲什么,boost::asio的文档自然是需要从www.boost.org上去下。

基本上,网络编程领域的”Hello World”程序就是类似Echodaytime等服务器应用了。大牛Stevens经典的《Unix Network Programming》一书更是在这两个服务器上折腾了半本书,Comer的《Internetworking With TCP/IP vol III》也不例外。boost::asio的文档也就更不例外了,全部的网络方面的例子都是以daytime服务为蓝本来讲解的。呵呵,大家这样做是有道理的,毕竟从讲解网络编程的原理来看,echo,daytime等足够的简单:)

 

二、    Tutorial

首先,因为客户端程序相对服务器程序更为简单,所以一般都从客户端开始,boost::asio也是如此,第一节,给出了一个TCP Daytime的实现所谓示例,这里,我不拷贝其源码了,只是列出一个用windows 下用套接字接口实现的同样程序作为对比。

1.      A synchronous TCP daytime client(一个同步的TCP daytime客户端程序)

原始的套接字实现:

#include <stdio.h>

#include <string.h>

#include "Winsock2.h"

#include "errno.h"

扫描二维码关注公众号,回复: 4996298 查看本文章

#include "stdlib.h"

 

#define MAXLINE 1000

void str_cli(SOCKET sockfd)

{

    char recvline[MAXLINE] = {0};

    while ( (recv(sockfd, recvline, MAXLINE, 0)) != NULL)

    {

       printf("%s", recvline);

    }

    closesocket(sockfd);

}

 

 

int main(int argc, char **argv)

{

    WORD wVersionRequested = 0;

    WSADATA wsaData;

    int err;

 

    wVersionRequested = MAKEWORD( 2, 2 );

 

    // windows下此初始化为必须,实际是初始化WinsockDLL的过程

    err = WSAStartup( wVersionRequested, &wsaData );

    if ( err != 0 ) {

       return -1;

    }

    SOCKET               sockfd;

    struct sockaddr_in   servaddr;

 

    if (argc != 2)

    {

       printf("usage: tcpcli <IPaddress>");

       exit(1);

    }

 

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

 

    ZeroMemory(&servaddr, sizeof(servaddr));

    servaddr.sin_family = AF_INET;

    servaddr.sin_port = htons(13);

    servaddr.sin_addr.s_addr = inet_addr(argv[1]);

 

    if( SOCKET_ERROR == connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)))

    {

       printf("connet failed, Error Code: %d", WSAGetLastError());

       closesocket(sockfd);

       return -1;

    }

 

    str_cli(sockfd);     /* do it all */

 

    system("pause");

    exit(0);

}

 

共六十一行,并且需要处理socket创建,初始化等繁琐细节,做任何决定时基本上是通过typecode,其实相对来说也不算太难,因为除了socketAPI接口属于需要额外学习的东西,没有太多除了C语言以外的东西需要学习,并且因为BSD socket是如此的出名,以至于几乎等同与事实的标准,所以这样的程序能被大部分学习过一定网络编程知识的人了解。

 

为了方便对比,我还是贴一下boost::asio示例中的代码:

#include <iostream>

#include <boost/array.hpp>

#include <boost/asio.hpp>

using boost::asio::ip::tcp;

 

int main(int argc, char* argv[])

{

    try

    {

       if (argc != 2)

       {

           std::cerr << "Usage: client <host>" << std::endl;

           return 1;

       }

       boost::asio::io_service io_service;

       tcp::resolver resolver(io_service);

       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::system::error_code error = boost::asio::error::host_not_found;

       while (error && endpoint_iterator != end)

       {

           socket.close();

           socket.connect(*endpoint_iterator++, error);

       }

       if (error)

           throw boost::system::system_error(error);

       for (;;)

       {

           boost::array<char, 128> buf;

           boost::system::error_code error;

           size_t len = socket.read_some(boost::asio::buffer(buf), error);

           if (error == boost::asio::error::eof)

              break; // Connection closed cleanly by peer.

           else if (error)

              throw boost::system::system_error(error); // Some other error.

           std::cout.write(buf.data(), len);

       }

    }

    catch (std::exception& e)

    {

       std::cerr << e.what() << std::endl;

    }

    return 0;

}

 

boost::asio的文档中的实现也有47行,用了多个try,catch来处理异常,因为其实现的原因,引入了较多的额外复杂度,除了boost::asio以外,即便你很熟悉C++,你也得进一步的了解诸如boost::array, boost:system等知识,(虽然其实很简单)并且,从使用上来说,感觉并没有比普通的socket API简单,虽然如此,boost::asio此例子还是有其优势的,比如ipv4,ipv6的自适应(原socket API仅仅支持ipv4),出错时更人性化的提示(此点由C++异常特性支持,相对比C语言中常常只能有个error code)

当然,此例子过于简单,而asio是为了较大规模程序的实现而设计的,假如这么小规模的程序用原始的套接字就足够了。这点是需要说明的。

 

2.      Daytime.2 - A synchronous TCP daytime server(同步的TCP daytime服务器)

有了客户端没有服务器,那客户端有什么用呢?^^所以,接下来boost::asio适时的给出了一个daytime的服务器实现,这里还是先给出使用一个原始套接字的例子:

#include <time.h>

#include "Winsock2.h"

#include "errno.h"

#include "stdlib.h"

 

#define MAXLINE 1000

int main(int argc, char **argv)

{

    WORD wVersionRequested = 0;

    WSADATA wsaData;

    int err;

 

    wVersionRequested = MAKEWORD( 2, 2 );

 

    // windows下此初始化为必须,实际是初始化WinsockDLL的过程

    err = WSAStartup( wVersionRequested, &wsaData );

    if ( err != 0 ) {

       return -1;

    }

 

    SOCKET               listenfd, connfd;

    struct sockaddr_in   servaddr;

    char              buff[MAXLINE];

    time_t            ticks;

 

    listenfd = socket(AF_INET, SOCK_STREAM, 0);

 

    ZeroMemory(&servaddr, sizeof(servaddr));

    servaddr.sin_family      = AF_INET;

    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    servaddr.sin_port        = htons(13);  /* daytime server */

 

    if( bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr))

        == SOCKET_ERROR)

    {

           printf("bind failed: %d/n", WSAGetLastError());

           closesocket(listenfd);

           WSACleanup();

           return 1;

    }

 

    if (listen( listenfd, SOMAXCONN ) == SOCKET_ERROR)

    {

       printf("Error listening on socket./n");

       WSACleanup();

       return 1;

    }

 

猜你喜欢

转载自blog.csdn.net/rgjtfc/article/details/86552849