Linux下Socket编程之TCP应用

现在,我们用前面所构建的socket类,重新设计《Linux下Socket编程之TCP Server端》中echo的服务器,然后设计客户端程序。
echo服务器的工作原理很简单:
1、接收客户端传来的信息;
2、将接收到的信息原封不动的返回给客户端。
可以看到我们所设计的TCPServerSock类具备了echo服务的所有数据成员,我们只需要添加一个具体的echo方法。因此,我们让设计的echo类从TCPServerSock类中派生出来。

// Filename AppSock.hpp

#ifndef APP_SOCK_HPP
#define  APP_SOCK_HPP

#include  " SockClass.hpp "

class  TCPEchoServer:  public  TCPServerSock{
public :
    TCPEchoServer(
         const  TCPListenSock &  listen_sock,
         int  pre_buffer_size  =   32 );
     ~ TCPEchoServer();
     bool  handEcho()  const ;
};

#endif   // AppSock.hpp
将handEcho()设计成返回值为bool是出于以下考虑:因为服务器端通常是无限循环提供服务的,我们希望客户端能简单的对服务器端的控制,比如说进行关闭,这样就不用每次用Ctrl+c来关闭服务器端的程序。所以,handlEcho()返回true表示客户端正常断开,false表示服务器被要求终止。
// Filename: AppSock.cpp

#include  < string >
#include  " AppSock.hpp "

TCPEchoServer::TCPEchoServer( const  TCPListenSock &  listen_sock,  int  pre_buffer_size):
TCPServerSock(listen_sock, pre_buffer_size)
{}

TCPEchoServer:: ~ TCPEchoServer()
{}

bool  TCPEchoServer::handEcho()  const
{
     const  std:: string  SHUTDOWN_CMD  =   " /shutdown " ;
     while  (TCPReceive()  >   0 ) {
        std:: string  cmd(preBuffer, SHUTDOWN_CMD.size());
         if  (cmd  ==  SHUTDOWN_CMD  &&  preReceivedLength  ==  ( int )SHUTDOWN_CMD.size()) {
             return   false ;
        }
        TCPSend(preBuffer, preReceivedLength);
    }
     return   true ;
}
我们为服务器指定一个关闭的的特殊字符串/shutdown,如果客户端传来这个字符串,服务器就会终止;其他字符串则会履行echo服务。
最后我们设计主程序:
// Filename: main.cpp

#include  " SockClass.hpp "
#include  " AppSock.hpp "

int  main( int  argc,  char *  argv[])
{
     const  unsigned  short  DEFAULT_PORT  =   5000 ;
    unsigned  short  listen_port  =  DEFAULT_PORT;
     if  (argc  ==   2   &&  atoi(argv[ 1 ])  >   0 ) {
        listen_port  =  atoi(argv[ 1 ]);
    }

    TCPListenSock listen_sock(listen_port);
    listen_sock.TCPListen();

     bool  go_on  =   true ;
     while  (go_on){
        TCPEchoServer echo_server(listen_sock);
        go_on  =  echo_server.handEcho();
    }

     return   0 ;
}

主程序以第一个参数(argv[1])来指定服务器端口,如果不指定,则默认端口是5000。 
本节源代码下载:
Linux:
http://www.163pan.com/files/c0x000g0o.html
win32:
http://www.163pan.com/files/c0x000g0q.html

 

echo客户端的工作原理也很简单:
1、向服务器端发送一个字符串;
2、接收服务器的返回信息(如果是echo服务器就会返回发送出去的字符串本身)。
3、在标准输出中回显服务器返回的信息。
与ehco服务器类似,我们的echo客户端类也可以从TCPClientSock中派生出来:

// Filename AppSock.hpp

#ifndef APP_SOCK_HPP
#define  APP_SOCK_HPP

#include  < string >
#include  " SockClass.hpp "

class  TCPEchoClient:  public  TCPClientSock{
public :
    TCPEchoClient(
         const   char *  server_IP,
        unsigned  short  server_port,
         int  pre_buffer_size  =   32 );
     ~ TCPEchoClient();
     bool  doEcho( const  std:: string &  echo_message)  const ;
};

#endif   // AppSock.hpp
我们的doEcho()接收一个C++风格的字符串(std::string),将返回值设计成bool是出于以下考虑:我们希望与服务器断开连接的信息能反馈到主程序中,并且在断开连接后终止echo客户端的程序。所以,返回true表示仍然与服务器保持连接,否则则已经断开(或者异常)。
#include  " AppSock.hpp "

TCPEchoClient::TCPEchoClient(
                 const   char *  server_IP,
                unsigned  short  server_port,
                 int  pre_buffer_size):
TCPClientSock(server_IP, server_port, pre_buffer_size)
{}

TCPEchoClient:: ~ TCPEchoClient()
{}

bool  TCPEchoClient::doEcho( const  std:: string &  echo_message)  const
{
     if  (TCPSend(echo_message.data(), echo_message.size())  <   0 ) {
         return   false ;
    }
    size_t total_received_length  =   0 ;
     while  (total_received_length  <  echo_message.size()) {
         if  (TCPReceive()  <=   0 ) {
             return   false ;
        }
        std::cout.write(preBuffer, preReceivedLength);
        total_received_length  +=  preReceivedLength;
    }
    std::cout  <<  std::endl;
     return   true ;
}
因为我们是先发再收,我们接收前是知道应该收到多少字节的信息的。由于TCP协议对边缘的无保障,我们应该假定是是最不利的情况,也就是一次recv()不能接收完我们需要的数据,所以,如果接收到的字节数小于我们的预期,就再次接收,直到跟我们发送的字符串长度一样。虽然事实上在这种小数据的传输中很难遇到以上所描述的那种情况,但是在网络程序的设计中,应该坚持这样一个基本假设:你永远不知道远程的主机会出什么状况,所以永远以最坏的可能性来设计程序。
最后是主程序。主程序在标准输入中阻塞等待用于echo的信息,为了避免无限循环,我们也设计一个可以关闭服务器端的命令/exit。这样,输入/exit或者服务器断开都可以导致客户端终止。
#include  " SockClass.hpp "
#include  " AppSock.hpp "

int  main( int  argc,  char *  argv[])
{
    unsigned  short  server_port  =   5000 ;
     if  (argc  ==   3   &&  atoi(argv[ 2 ])  >   0 ) {
        server_port  =  atoi(argv[ 2 ]);
    }
    
    WinsockAPI winsockInfo;
    winsockInfo.showVersion();

    TCPEchoClient echo_client(argv[ 1 ], server_port);
    std:: string  msg;
     bool  go_on  =   true ;
     while  (msg  !=   " /exit "   &&  go_on  ==   true ) {
        std::cout  <<   " Echo:  " ;
        std::getline(std::cin, msg);
        go_on  =  echo_client.doEcho(msg);
    }

     return   0 ;
}
本节源代码下载:
linux:
http://www.163pan.com/files/c0x000g0x.html
win32:
http://www.163pan.com/files/c0x000g0y.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值