这篇文章主要介绍一下,如何使用 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
-
/**
-
in this file i would like create a pair of myPipe
-
myPipe[0] is used to read from myPipe's contents
-
myPipe[1] is used to write into myPipe's contents
-
and the sock_fd is the socket descriptor used to
-
listen to the target port
-
I would like create a class , write all the method (initialize connect and other thing)
-
into the class's constructor
-
and packed write , read myPipe's contents into the class too
-
-
by Aimer 2015/5/16
-
***/
-
-
#ifndef PIPE_H__
-
#define PIPE_H__
-
-
-
-
class myPipe
-
{
-
public :
-
myPipe () ;
-
~myPipe () ;
-
int write_in_pipe ( const void *buf , int len ) ;
-
int read_from_pipe ( void *buf , int len ) ;
-
int get_read_descr () ;
-
-
private :
-
int pipes[2] ;
-
-
} ;
-
-
-
#endif // myPipe.h
// myPipe.cpp
-
#include <sys/types.h>
-
#include <sys/socket.h>
-
#include <unistd.h>
-
#include <netinet/in.h>
-
#include <arpa/inet.h>
-
-
-
#include <cstdio>
-
#include <errno.h>
-
#include <time.h>
-
-
#include "my_pipe.h"
-
-
/**
-
in class myPipe
-
pipes[0] ---- > is equal to the server's readin socket descriptor
-
and server's accept method return socket descriptor
-
pipes[1] ---- > is just like the client's write in socket descriptor
-
-
socket_fd ---> is like the server's listen socket descriptor
-
*/
-
-
-
myPipe::myPipe ()
-
{
-
int sock_fd = 0 ;
-
int ret = 0 ;
-
-
struct timeval timeout = {0,0} ; // 0 s
-
-
static int port_num = 1027 ;
-
struct sockaddr_in sock_addr ;
-
-
sock_fd = (int) socket( AF_INET , SOCK_STREAM , IPPROTO_TCP ) ;
-
-
if ( 0 > sock_fd )
-
{
-
perror (" socket error ") ;
-
return ;
-
}
-
-
pipes[1] = (int) socket (AF_INET , SOCK_STREAM , IPPROTO_TCP ) ;
-
-
if ( 0 > pipes[1] )
-
{
-
// if we apply for client's socket fd failed , do not forget
-
// close sock_fd
-
close ( sock_fd ) ;
-
return ;
-
}
-
-
/* here we initialize the address */
-
sock_addr.sin_addr.s_addr = inet_addr ("127.0.0.1") ; // we use the loop address
-
sock_addr.sin_family = AF_INET ;
-
-
int try_times = 25 ; // we would like try 25 times until we get a appropriate ip port
-
-
// you may wonder what's the definition of an appropriate port ?
-
// here it is : set the appropriate port to the sock_addr
-
// and then bind the sock_addr to the sock_fd correctly
-
// the port is the so-called appropriate
-
-
-
while ( port_num++ && try_times-- > 0 )
-
{
-
sock_addr.sin_port = htons ( (short) port_num ) ;
-
-
if ( bind ( sock_fd , (struct sockaddr *)&sock_addr , sizeof(sock_addr)) < 0 )
-
{
-
// on ,port_num is not good , we have to increase it by 1
-
perror ("failed bind the socke_addr to sock_fd ") ;
-
}
-
-
else
-
// this branch we get the appropriate port we want
-
break ;
-
}
-
//-------------while end -------------------
-
-
if ( try_times == 0 ) // this means we tried try_times and we didn't get the port num we want
-
{
-
perror ("failed to get correct port which can bind to sock_fd") ;
-
-
// do not forget close the two socket descriptor
-
close ( sock_fd ) ;
-
close ( pipes[1] ) ;
-
-
return ;
-
}
-
-
// ---------- if we get here , that means we got correct port num and finish binding----------------
-
-
ret = listen ( sock_fd , 1 ) ; // 1 means listen-back queue length is limited to 1
-
-
if ( ret != 0 )
-
{
-
perror ( "failed to execute listen ") ;
-
-
// this branch means listen method failed
-
close ( sock_fd ) ;
-
close ( pipes[1] ) ;
-
return ;
-
}
-
-
// method following is used to set receiving buffer size
-
-
ret = setsockopt ( pipes[1] , SOL_SOCKET , SO_RCVTIMEO , &timeout ,sizeof(timeout) );
-
-
if ( ret != 0 ) // this means setsockopt met error
-
{
-
perror ("failed to execute setsocket method ") ;
-
printf ("ret %d errno : %d \n" , ret , errno ) ;
-
close ( sock_fd ) ;
-
close ( pipes[1] ) ;
-
return ;
-
}
-
-
// here we use the write myPipe connect to local loop address
-
-
ret = connect ( pipes[1] , (struct sockaddr *)&sock_addr , sizeof ( sock_addr )) ;
-
-
if ( ret != 0 ) // something wrong
-
{
-
perror ("failed to execute connect method ") ;
-
close ( pipes[1] ) ;
-
close ( sock_fd ) ;
-
-
return ;
-
}
-
-
// here we use the accept method to accept
-
// connection requests send to sock_fd
-
-
pipes[0] = accept ( sock_fd , NULL , NULL ) ;
-
-
if ( pipes[0] <= 0 ) // something wrong with accept
-
{
-
perror ("failed to execute accept method ") ;
-
close ( pipes[1] ) ;
-
close ( sock_fd ) ;
-
-
return ;
-
}
-
-
-
printf ("you create a pipe successfully \n") ;
-
-
}
-
-
myPipe::~myPipe ()
-
{
-
close ( pipes[0] ) ;
-
close ( pipes[1] ) ;
-
}
-
-
/**
-
method write contents into myPipe
-
use myPipes[1] as descriptor
-
const is used to let the method caller could not change
-
the value of the pointer , cause the content space is read-only
-
buf -> pointer points to the to be written space
-
len -> length of to be written content space
-
**/
-
int myPipe::write_in_pipe ( const void *buf , int len )
-
{
-
return send ( pipes[1] , ( const char *) buf , len , 0 ) ;
-
}
-
-
/**
-
both send and recv method 's 0 here means :
-
if no one receives ( sends ) data from ( to ) me
-
i will not blocked waitting
-
*/
-
-
int myPipe::read_from_pipe ( void *buf , int len )
-
{
-
return recv ( pipes[0] , (char *)buf , len , 0 ) ;
-
}
-
-
int myPipe::get_read_descr ()
-
{
-
return pipes[0] ;
-
}
// Main.cpp
-
/**
-
in this file used to test pipe class ' s method
-
**/
-
-
#include <cstdio>
-
#include <string.h>
-
#include <cstdlib>
-
#include <iostream>
-
-
#include "my_pipe.h"
-
-
using namespace std ;
-
-
int main ( int argc , char ** argv )
-
{
-
char *strPtr ;
-
string line_in ;
-
-
cout << "input a line " << endl ;
-
-
cin >> line_in ;
-
-
strPtr = (char *)malloc (1024*sizeof(char)) ;
-
-
cout <<"----- ok here we test pipe write and read ---------" <<endl ;
-
-
-
myPipe p ;
-
-
p.write_in_pipe ( line_in.c_str() , line_in.size() ) ;
-
-
p.read_from_pipe ( strPtr , 1024 ) ;
-
-
cout << "here is what read from pipe " << endl ;
-
cout << strPtr << endl ;
-
-
return 0 ;
-
}
end
阅读(1923) | 评论(0) | 转发(0) |