zoukankan      html  css  js  c++  java
  • freecplus框架-tcp网络通信

    一、源代码说明

    freecplus是一个Linux系统下的C/C++开源框架,源代码请前往C语言技术网(www.freecplus.net)下载。

    本文介绍的是freecplus框架的TCP/IP协议网络通信的函数和类。

    函数和类的声明文件是freecplus/_freecplus.h。

    函数和类的定义文件是freecplus/_freecplus.cpp。

    示例程序位于freecplus/demo目录中。

    编译规则文件是freecplus/demo/makefile。

    二、概述

    freecplus框架对socket通信封装如下:

    CTcpClient类:socket通信的客户端类。

    CTcpServer类:socket通信的服务端类。

    TcpRead函数:接收socket的对端发送过来的数据。

    TcpWrite函数:向socket的对端发送数据。

    Readn函数:从已经准备好的socket中读取数据。

    Writen函数:向已经准备好的socket中写入数据。

    在阅读本文章之前,您必须熟悉TCP/IP协议和socket通信,本文是介绍的是freecplus框架中网络通信的类和函数的用法,不会介绍网络通信的基础知识。

    三、通信的报文格式

    freecplus框架的socket通信报文格式如下:

    报文长度+报文内容

    报文长度为4字节的整数,表示的是报文内容的长度,而不是整个TCP报文的长度,整个TCP报文的长度是报文内容的长度+4

    报文长度是4字节的整数,即int,是以二进制流的方式写入socket,不是ascii码。

    采用CTcpClient类、CTcpServer类、TcpRead函数和TcpWrite函数进行socket通信,可以避免TCP报文粘包的问题。

    四、socket通信客户端

    socket通信的客户端封装在CTcpClient类中。

    类的声明:

    // socket通信的客户端类
    class CTcpClient
    {
    public:
      int  m_sockfd;    // 客户端的socket.
      char m_ip[21];    // 服务端的ip地址。
      int  m_port;      // 与服务端通信的端口。
      bool m_state;     // 与服务端的socket连接状态。
      bool m_btimeout;  // 调用Read和Write方法时,失败的原因是否是超时:true-未超时,false-已超时。
      int  m_buflen;    // 调用Read方法后,接收到的报文的大小,单位:字节。
    
      CTcpClient();  // 构造函数。
    
      // 向服务端发起连接请求。
      // ip:服务端的ip地址。
      // port:服务端监听的端口。
      // 返回值:true-成功;false-失败。
      bool ConnectToServer(const char *ip,const int port);
    
      // 接收服务端发送过来的数据。
      // buffer:接收数据缓冲区的地址,数据的长度存放在m_buflen成员变量中。
      // itimeout:等待数据的超时时间,单位:秒,缺省值是0-无限等待。
      // 返回值:true-成功;false-失败,失败有两种情况:1)等待超时,成员变量m_btimeout的值被设置为true;2)socket连接已不可用。
      bool Read(char *buffer,const int itimeout=0);
    
      // 向服务端发送数据。
      // buffer:待发送数据缓冲区的地址。
      // ibuflen:待发送数据的大小,单位:字节,缺省值为0,如果发送的是ascii字符串,ibuflen取0,如果是二进制流数据,ibuflen为二进制数据块的大小。
      // 返回值:true-成功;false-失败,如果失败,表示socket连接已不可用。
      bool Write(const char *buffer,const int ibuflen=0);
    
      // 断开与服务端的连接
      void Close();
    
      ~CTcpClient();  // 析构函数自动关闭socket,释放资源。
    };
    

    五、socket通信的服务端

    socket通信的服务端封装在CTcpServer类中。

    类的声明:

    // socket通信的服务端类
    class CTcpServer
    {
    private:
      int m_socklen;                    // 结构体struct sockaddr_in的大小。
      struct sockaddr_in m_clientaddr;  // 客户端的地址信息。
      struct sockaddr_in m_servaddr;    // 服务端的地址信息。
    public:
      int  m_listenfd;   // 服务端用于监听的socket。
      int  m_connfd;     // 客户端连接上来的socket。
      bool m_btimeout;   // 调用Read和Write方法时,失败的原因是否是超时:true-未超时,false-已超时。
      int  m_buflen;     // 调用Read方法后,接收到的报文的大小,单位:字节。
    
      CTcpServer();  // 构造函数。
    
      // 服务端初始化。
      // port:指定服务端用于监听的端口。
      // 返回值:true-成功;false-失败,一般情况下,只要port设置正确,没有被占用,初始化都会成功。
      bool InitServer(const unsigned int port); 
    
      // 阻塞等待客户端的连接请求。
      // 返回值:true-有新的客户端已连接上来,false-失败,Accept被中断,如果Accept失败,可以重新Accept。
      bool Accept();
    
      // 获取客户端的ip地址。
      // 返回值:客户端的ip地址,如"192.168.1.100"。
      char *GetIP();
    
      // 接收客户端发送过来的数据。
      // buffer:接收数据缓冲区的地址,数据的长度存放在m_buflen成员变量中。
      // itimeout:等待数据的超时时间,单位:秒,缺省值是0-无限等待。
      // 返回值:true-成功;false-失败,失败有两种情况:1)等待超时,成员变量m_btimeout的值被设置为true;2)socket连接已不可用。
      bool Read(char *buffer,const int itimeout);
    
      // 向客户端发送数据。
      // buffer:待发送数据缓冲区的地址。
      // ibuflen:待发送数据的大小,单位:字节,缺省值为0,如果发送的是ascii字符串,ibuflen取0,如果是二进制流数据,ibuflen为二进制数据块的大小。
      // 返回值:true-成功;false-失败,如果失败,表示socket连接已不可用。
      bool Write(const char *buffer,const int ibuflen=0);
    
      // 关闭监听的socket,即m_listenfd,常用于多进程服务程序的子进程代码中。
      void CloseListen();
    
      // 关闭客户端的socket,即m_connfd,常用于多进程服务程序的父进程代码中。
      void CloseClient();
    
      ~CTcpServer();  // 析构函数自动关闭socket,释放资源。
    };
    

    六、示例程序

    1、客户端

    示例(demo47.cpp)

    /*
     *  程序名:demo47.cpp,此程序演示采用freecplus框架的CTcpClient类实现socket通信的客户端。
     *  作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include "../_freecplus.h"
    
    int main(int argc,char *argv[])
    {
      CTcpClient TcpClient;   // 创建客户端的对象。
      
      if (TcpClient.ConnectToServer("172.16.0.15",5858)==false) // 向服务端发起连接请求。
      {
        printf("TcpClient.ConnectToServer("172.16.0.15",5858) failed.
    "); return -1;
      }
    
      char strbuffer[1024];    // 存放数据的缓冲区。
    
      for (int ii=0;ii<5;ii++)   // 利用循环,与服务端进行5次交互。
      {
        memset(strbuffer,0,sizeof(strbuffer));
        snprintf(strbuffer,50,"这是第%d个超级女生,编号%03d。",ii+1,ii+1);
        printf("发送:%s
    ",strbuffer);
        if (TcpClient.Write(strbuffer)==false) break;    // 向服务端发送请求报文。
    
        memset(strbuffer,0,sizeof(strbuffer));
        if (TcpClient.Read(strbuffer,20)==false) break;  // 接收服务端的回应报文。
        printf("接收:%s
    ",strbuffer);
    
        sleep(1);
      }
    
      // 程序直接退出,析构函数会释放资源。
    }
    

    2、服务端

    示例(demo48.cpp)

    /*
     *  程序名:demo48.cpp,此程序演示采用freecplus框架的CTcpServer类实现socket通信的服务端。
     *  作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include "../_freecplus.h"
    
    int main(int argc,char *argv[])
    {
      CTcpServer TcpServer;   // 创建服务端对象。
      
      if (TcpServer.InitServer(5858)==false) // 初始化TcpServer的通信端口。
      {
        printf("TcpServer.InitServer(5858) failed.
    "); return -1;
      }
      
      if (TcpServer.Accept()==false)   // 等待客户端连接。
      {
        printf("TcpServer.Accept() failed.
    "); return -1;
      }
    
      printf("客户端(%s)已连接。
    ",TcpServer.GetIP());
    
      char strbuffer[1024];  // 存放数据的缓冲区。
    
      while (true)
      {
        memset(strbuffer,0,sizeof(strbuffer));
        if (TcpServer.Read(strbuffer,300)==false) break; // 接收客户端发过来的请求报文。
        printf("接收:%s
    ",strbuffer);
    
        strcat(strbuffer,"ok");      // 在客户端的报文后加上"ok"。
        printf("发送:%s
    ",strbuffer);
        if (TcpServer.Write(strbuffer)==false) break;     // 向客户端回应报文。
      }
    
      printf("客户端已断开。
    ");    // 程序直接退出,析构函数会释放资源。
    }
    

    3、运行程序前的准备端

    我希望您已经学过计算机网络的基础知识,在运行示例程序之前,请确保您的Linux操作系统已开通防火墙。

    在demo47.cpp和demo48.cpp程序中,服务端的ip地址和通信端口是写死在程序中的,请根据您的实际情况修改它们,然后重新编译。

    4、运行程序

    先启动demo48,然后启动demo47。

    demo47的运行效果如下:

    在这里插入图片描述

    demo48的运行效果如下:

    在这里插入图片描述

    七、socket通信的函数

    采用CTcpClient和CTcpServer类实现socket通信功能非常方便,但是在实际开发中,某些场景中不能只依赖这两个类,例如多程线和异步通信等场景,还必须结合以下将要介绍的几个函数一起使用。

    1、TcpRead函数

    接收socket的对端发送过来的数据。

    函数的声明:

    bool TcpRead(const int sockfd,char *buffer,int *ibuflen,const int itimeout=0);
    

    参数说明:

    sockfd:可用的socket连接。

    buffer:接收数据缓冲区的地址。

    ibuflen:本次成功接收数据的字节数。

    itimeout:接收等待超时的时间,单位:秒,缺省值是0-无限等待。

    返回值:true-成功;false-失败,失败有两种情况:1)等待超时;2)socket连接已不可用。

    在CTcpClient和CTcpServer类的Read方法中调用了TcpRead函数。

    2、TcpWrite函数

    向socket的对端发送数据。

    函数的声明:

    bool TcpWrite(const int sockfd,const char *buffer,const int ibuflen=0);
    

    参数说明:

    sockfd:可用的socket连接。

    buffer:待发送数据缓冲区的地址。

    ibuflen:待发送数据的字节数,如果发送的是ascii字符串,ibuflen取0,如果是二进制流数据,ibuflen为二进制数据块的大小。

    返回值:true-成功;false-失败,如果失败,表示socket连接已不可用。

    在CTcpClient和CTcpServer类的Write方法中调用了TcpRead函数。

    3、Readn函数

    从已经准备好的socket中读取数据。

    函数的声明:

    bool Readn(const int sockfd,char *buffer,const size_t n);
    

    sockfd:已经准备好的socket连接。

    buffer:接收数据缓冲区的地址。

    n:本次接收数据的字节数。

    返回值:成功接收到n字节的数据后返回true,socket连接不可用返回false。

    注意:

    1)sockfd是已经准备好的socket连接,那什么是已经准备好的socket?在这个socket上,已经或马上有n字节的数据一定会到达。

    2)成功接收到n字节的数据后返回true,如果没有n字节的数据怎么办?不会,在1)中已经说明了,一定会有n字节的数据会到达。

    3)如果数据大于n字节怎么办?Readn只读取n个字节的数据,其它的数据属于其它的报文。

    4)socket的对端是采用Writen方法写入的数据。

    在TcpRead函数中,调用了Readn函数。

    4、Writen函数

    向已经准备好的socket中写入数据。

    函数的声明:

    bool Writen(const int sockfd,const char *buffer,const size_t n);
    

    sockfd:已经准备好的socket连接。

    buffer:待发送数据缓冲区的地址。

    n:待发送数据的字节数。

    返回值:成功发送完n字节的数据后返回true,socket连接不可用返回false。

    在TcpWrite函数中,调用了Writen函数。

    八、版权声明

    C语言技术网原创文章,转载请说明文章的来源、作者和原文的链接。
    来源:C语言技术网(www.freecplus.net)
    作者:码农有道

    如果文章有错别字,或者内容有错误,或其他的建议和意见,请您留言指正,非常感谢!!!

  • 相关阅读:
    昂达 v891 连接上adb 调试
    在不进入Guest OS的情况下,取得Guest OS的IP地址
    在远程连接一个 Wndows 10的情况下,重启远程机器
    放弃 Tightvnc, 选择 Tigervnc
    Ubuntu 16.04 构建 Headless VNC 服务器
    网站日志流量分析系统之数据可视化展示
    网站日志流量分析系统之离线分析(自动化脚本)
    网站日志流量分析系统之数据清洗处理(离线分析)
    网站日志流量分析系统之(日志收集)
    网站日志流量分析系统之(日志埋点)
  • 原文地址:https://www.cnblogs.com/wucongzhou/p/12613822.html
Copyright © 2011-2022 走看看