Chinaunix首页 | 论坛 | 博客
  • 博客访问: 584634
  • 博文数量: 104
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1559
  • 用 户 组: 普通用户
  • 注册时间: 2014-08-21 00:58
个人简介

锻炼精神,首先要锻炼肉体

文章分类

全部博文(104)

文章存档

2018年(1)

2016年(1)

2015年(101)

2014年(1)

我的朋友

分类: C/C++

2015-05-16 11:39:59

这篇文章主要介绍一下,如何使用 pipe ,并且如何将 pipe 封装到一个类中。
在下面的 myPipe 类中,有一个 int pipes[2] 的私有变量。
这个整型数组变量中所对应的 pipes[0] , pipes[1] 对应的分别作为管道通信双端的读取描述符,和写入描述符。

如果看过前面的 client , server 通信代码实例的话,可以将这里的 pipes[0] 当做是服务器端创建的通过监听端口
获取(accept)的来自客户端的连接请求所返回的套接字的描述符。
而 pipes[1] 相当于是 client 端用于向 server 端发送请求而申请并且通过 connect 方法设定的 socket 描述符。

我们将一系列 server 端中的 : socket 创建,绑定 bind , 监听 listen, 接收 accept  (sock_fd  accept ---- > pipes[0] )
和 client 端中的 : socket 创建,发送连接请求 connect 等 方法全部包含在 myPipe 类的构造方法中,而 ip 地址使用的是
主机自身的回环访问地址 "127.0.0.1". 这个 socket_in 结构体被类中的 发送端,接收端,以及作为服务器的监听端所公用。

这样每创建一个 myPipe 对象,便会完成上述一系列的操作,并且初始化好一个可供通信的 pipe pair .

调用 myPipe 类实例对象的成员方法 write_in_pipe 便可以将数据写入到 pipe 中
调用 myPipe 类实例对象的成员方法 read_from_pipe 便可以将数据从 pipe 中读出

在编写此代码之前,我没有太深入的从管道(pipe)的定义来了解它, 通过这个实例,我对管道的理解便是,
计算机在进行通信的时候,用于传输通信数据而在系统中开辟的一块缓冲空间,类似于一个缓冲文件,
分别设定两个 读取,写入 操作的文件描述符,使用者可以通过这两个文件描述符来向缓冲文件中 写入数据或是读取内容。
等到通信一结束,缓冲文件将会被系统所释放,而这个释放的操作便是通过使用者 close ( 读文件描述符) close( 写文件描述符)

恰巧我们创建的缓冲文件是通过 socket 描述符所创建的,这也就是说,如果我们使用一个真正的文件作为提供缓冲的载体也是可以的。

// myPipe.h

点击(此处)折叠或打开

  1. /**
  2.   in this file i would like create a pair of myPipe
  3.   myPipe[0] is used to read from myPipe's contents
  4.   myPipe[1] is used to write into myPipe's contents
  5.   and the sock_fd is the socket descriptor used to
  6.   listen to the target port
  7.   I would like create a class , write all the method (initialize connect and other thing)
  8.   into the class's constructor
  9.   and packed write , read myPipe's contents into the class too
  10.   
  11.   by Aimer 2015/5/16
  12. ***/

  13. #ifndef PIPE_H__
  14. #define PIPE_H__



  15. class myPipe
  16. {
  17.   public :
  18.     myPipe () ;
  19.     ~myPipe () ;
  20.         int write_in_pipe     ( const void *buf , int len ) ;
  21.         int read_from_pipe     ( void *buf , int len ) ;
  22.     int get_read_descr     () ;
  23.     
  24.  private :
  25.     int pipes[2] ;

  26. } ;


  27. #endif // myPipe.h

// myPipe.cpp

点击(此处)折叠或打开

  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <unistd.h>
  4. #include <netinet/in.h>
  5. #include <arpa/inet.h>


  6. #include <cstdio>
  7. #include <errno.h>
  8. #include <time.h>

  9. #include "my_pipe.h"

  10. /**
  11.   in class myPipe
  12.   pipes[0] ---- > is equal to the server's readin socket descriptor
  13.            and server's accept method return socket descriptor
  14.   pipes[1] ---- > is just like the client's write in socket descriptor
  15.   
  16.   socket_fd ---> is like the server's listen socket descriptor
  17. */


  18. myPipe::myPipe ()
  19. {
  20.   int sock_fd = 0 ;
  21.   int ret = 0 ;

  22.   struct timeval timeout = {0,0} ; // 0 s

  23.   static int port_num = 1027 ;
  24.   struct sockaddr_in sock_addr ;
  25.   
  26.   sock_fd = (int) socket( AF_INET , SOCK_STREAM , IPPROTO_TCP ) ;
  27.  
  28.   if ( 0 > sock_fd )
  29.   {
  30.       perror (" socket error ") ;
  31.       return ;
  32.   }

  33.   pipes[1] = (int) socket (AF_INET , SOCK_STREAM , IPPROTO_TCP ) ;
  34.  
  35.   if ( 0 > pipes[1] )
  36.   {
  37.        // if we apply for client's socket fd failed , do not forget
  38.       // close sock_fd
  39.     close ( sock_fd ) ;
  40.         return ;
  41.   }

  42.   /* here we initialize the address */
  43.   sock_addr.sin_addr.s_addr = inet_addr ("127.0.0.1") ; // we use the loop address
  44.   sock_addr.sin_family = AF_INET ;

  45.   int try_times = 25 ; // we would like try 25 times until we get a appropriate ip port
  46.   
  47.   // you may wonder what's the definition of an appropriate port ?
  48.   // here it is : set the appropriate port to the sock_addr
  49.   // and then bind the sock_addr to the sock_fd correctly
  50.  // the port is the so-called appropriate


  51.   while ( port_num++ && try_times-- > 0 )
  52.   {
  53.     sock_addr.sin_port = htons ( (short) port_num ) ;
  54.     
  55.     if ( bind ( sock_fd , (struct sockaddr *)&sock_addr , sizeof(sock_addr)) < 0 )
  56.     {
  57.         // on ,port_num is not good , we have to increase it by 1
  58.         perror ("failed bind the socke_addr to sock_fd ") ;
  59.         }
  60.     
  61.     else
  62.         // this branch we get the appropriate port we want
  63.         break ;
  64.   }
  65. //-------------while end -------------------
  66.  
  67.  if ( try_times == 0 ) // this means we tried try_times and we didn't get the port num we want
  68.  {
  69.     perror ("failed to get correct port which can bind to sock_fd") ;
  70.     
  71.     // do not forget close the two socket descriptor
  72.     close ( sock_fd ) ;
  73.     close ( pipes[1] ) ;
  74.     
  75.     return ;
  76.  }

  77. // ---------- if we get here , that means we got correct port num and finish binding----------------
  78.  
  79.  ret = listen ( sock_fd , 1 ) ; // 1 means listen-back queue length is limited to 1
  80.  
  81.  if ( ret != 0 )
  82.  {
  83.     perror ( "failed to execute listen ") ;

  84.     // this branch means listen method failed
  85.     close ( sock_fd ) ;
  86.     close ( pipes[1] ) ;
  87.     return ;
  88.  }
  89.  
  90. // method following is used to set receiving buffer size

  91. ret = setsockopt ( pipes[1] , SOL_SOCKET , SO_RCVTIMEO , &timeout ,sizeof(timeout) );
  92.  
  93. if ( ret != 0 ) // this means setsockopt met error
  94. {
  95.     perror ("failed to execute setsocket method ") ;
  96.     printf ("ret %d errno : %d \n" , ret , errno ) ;
  97.     close ( sock_fd ) ;
  98.     close ( pipes[1] ) ;
  99.     return ;
  100. }

  101. // here we use the write myPipe connect to local loop address

  102. ret = connect ( pipes[1] , (struct sockaddr *)&sock_addr , sizeof ( sock_addr )) ;

  103. if ( ret != 0 ) // something wrong
  104. {
  105.     perror ("failed to execute connect method ") ;
  106.     close ( pipes[1] ) ;
  107.     close ( sock_fd ) ;
  108.     
  109.     return ;
  110. }

  111. // here we use the accept method to accept
  112. // connection requests send to sock_fd

  113. pipes[0] = accept ( sock_fd , NULL , NULL ) ;

  114. if ( pipes[0] <= 0 ) // something wrong with accept
  115. {
  116.     perror ("failed to execute accept method ") ;
  117.         close ( pipes[1] ) ;
  118.     close ( sock_fd ) ;
  119.     
  120.     return ;
  121. }


  122.        printf ("you create a pipe successfully \n") ;

  123. }

  124. myPipe::~myPipe ()
  125. {
  126.     close ( pipes[0] ) ;
  127.     close ( pipes[1] ) ;
  128. }

  129. /**
  130.   method write contents into myPipe
  131.   use myPipes[1] as descriptor
  132.   const is used to let the method caller could not change
  133.   the value of the pointer , cause the content space is read-only
  134.   buf -> pointer points to the to be written space
  135.   len -> length of to be written content space
  136. **/
  137. int myPipe::write_in_pipe ( const void *buf , int len )
  138. {
  139.     return send ( pipes[1] , ( const char *) buf , len , 0 ) ;
  140. }

  141. /**
  142.   both send and recv method 's 0 here means :
  143.   if no one receives ( sends ) data from ( to ) me
  144.   i will not blocked waitting
  145. */

  146. int myPipe::read_from_pipe ( void *buf , int len )
  147. {
  148.     return recv ( pipes[0] , (char *)buf , len , 0 ) ;
  149. }

  150. int myPipe::get_read_descr ()
  151. {
  152.     return pipes[0] ;
  153. }

// Main.cpp

点击(此处)折叠或打开

  1. /**
  2.   in this file used to test pipe class ' s method
  3. **/
  4.  
  5. #include <cstdio>
  6. #include <string.h>
  7. #include <cstdlib>
  8. #include <iostream>

  9. #include "my_pipe.h"

  10. using namespace std ;

  11. int main ( int argc , char ** argv )
  12. {
  13.   char *strPtr ;
  14.   string line_in ;
  15.  
  16.   cout << "input a line " << endl ;

  17.   cin >> line_in ;
  18.    
  19.   strPtr = (char *)malloc (1024*sizeof(char)) ;
  20.  
  21. cout <<"----- ok here we test pipe write and read ---------" <<endl ;


  22.   myPipe p ;
  23.   
  24.   p.write_in_pipe ( line_in.c_str() , line_in.size() ) ;

  25.   p.read_from_pipe ( strPtr , 1024 ) ;

  26.   cout << "here is what read from pipe " << endl ;
  27.   cout << strPtr << endl ;

  28.   return 0 ;
  29. }
end
阅读(1947) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~