Linux程序输入、输出重定向

C/C++, Linux No Comments »

对于输出重定向大家应该都比较了解了,一般都是指把输出重定向到一个文件中,而对于输入重定向一般就不是很常用了。暂时的一个应用就是实现程序的脚本控制,比如你用脚本启动另一个程序,然后又需要给这个启动的程序发送命令,这时就需要采用输入重定向了,这对于一些服务类型的程序还是很有用的。要实现真正意义的输入重定向还是比较麻烦的,需要用到管道。

下面用一个简单的示例来实现程序的输入,输出重定向。

//file_name:shi_li.cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>

#define MAX_LINE 80
#define PIPE_STDIN  0
#define PIPE_STDOUT 1

int main(){
 int child_pid;

 char outPath[30];
 strcpy(outPath,"./out.file");

 int pfds[2];
 if (pipe(pfds)== 0){
  child_pid=fork();
  //in child process the return pid==0
  if ( child_pid == 0 ) {

   //input file,may be used later.
   //char inPath[30];
   //strcpy(inPath,"./in.file");

   //int inFd = open(inPath,O_RDWR|O_CREAT,S_IRUSR|S_IWUSR);
   int outFd = open(outPath,O_WRONLY|O_APPEND|O_CREAT,S_IRUSR);

   close(0);
   dup2( pfds[PIPE_STDIN], 0);
   dup2(outFd,1);
   close(pfds[PIPE_STDOUT]);
   execl("./getstring","getstring",NULL);
   printf("start getstring: error!!!");
   exit(1);
          }
  else {

   close(pfds[PIPE_STDIN]);
       char msg[MAX_LINE];
         int b=1;
        for(b=1;b<6;b++){              
           sleep(1);
             sprintf(msg,"2+%d\n",b); 
             write( pfds[PIPE_STDOUT], msg, strlen(msg) );              
                 }
         close(pfds[PIPE_STDOUT]);
         sleep(2);
         printf("all done.\n");
         }
       }
 return 0;
} 

接下来是一个很简单的程序输入:

//file_name: getstring.cpp

#include <unistd.h>
#include <iostream>
using namespace std;

int main(){ 
 string tmp;

 while(cin >> tmp,!cin.eof()){
  if(cin.bad()){  
   cerr<<"io stream error"<<endl;
   exit(1); 
  }
  if(cin.fail()){
   cerr<<"io stream error"<<endl;
   cin.clear(istream::failbit);
   continue;
  }
  //ok to process 
  cout<<"all done well:"<<tmp<<endl;
 }
}

编译并运行:

#g++ -o getstring getstring.cpp
#g++ -o shi_li shi_li.cpp
#./shi_li

上述代码包括两个小程序,getstring简单的接收输入的字符串并在终端上回显。shi_li程序负责启动getstring并把输入重定向到管道,输出重定向到out.file文件。执行代码后我们可以查看out.file文件来获得程序执行的结果。

上述小程序可以用在脚本时对向子程序发送命令,从而完成程序测试的自动化。上述代码只是个demo,如果想在实际测试中可用还需要根据自己的情况进行些许修改。

参考资料:

[1] http://blog.chinaunix.net/u/19573/showart_1225848.html

[2]http://www.opengroup.org/onlinepubs/009695399/

[转]Manufactoria:非常好玩的自动机编程游戏

BrainStorm 2 Comments »

这是我在Matrix67上看到的一个很好玩的自动机编程游戏。很遗憾我自己还没玩通关,呵呵。

游戏介绍:它是真正意义上的程序设计游戏,游戏不但提供了完备的读写和流程控制功能,甚至还引入了随机测试数据。游戏很快就会引入算法的思想,因为玩家渐渐会发现,这些谜题并不是单靠模拟就能解决的;后面的谜题则越发困难,需要相当有技巧性的算法设计,对脑力绝对是一个大挑战。如果你热爱算法与程序设计,你一定会爱上这个游戏的。

原文地址:http://www.matrix67.com/blog/archives/3306

游戏来源:http://jayisgames.com/games/manufactoria/

ubuntu下成功安装sfslite

C/C++, Linux No Comments »

之前曾采用MIT的开源chord来开发P2P的系统,由于chord依赖于sfslite的一些库文件,所以需要安装sfslite-0.8.16。自此带来了很多问题,因为sfslite需要gcc-4.1.2才能编译,用最新的gcc-4.3或4.4都会编译失败,而且它好像还和操作系统有关,在fedora 7下可以正常编译。如果您不想使用fedora 7这种老版本的系统那就麻烦了。

最近新安装了ubuntu 10,突然想在ubuntu下尝试一下,这样后续的开发就不用再装fedora 7的虚拟机了,而且也可以方便程序的移植。下面简要介绍安装的过程:

首先安装gcc-4.1.2,具体安装过程参考“在ubuntu中编译、安装gcc 4.1.1过程以及遇到的问题”,上面讲的很详细。主要有一个地方需要注意,gcc-4.1.2依赖texinfo库,默然configure不支持texinfo 4.10+,需要修改configure文件。在其中找到’texinfo[^0-9]*([1-3][0-9]|4\.[2-9]|[5-9])’编辑成’texinfo[^0-9]*([1-3][0-9]|4\.[2-9]|4\.[1-9][0-9]*|[5-9])’后保存,编译通过。[注] 无需修改LD_LIBRARY_PATH变量,在ubuntu下没有这个变量,因为已经被废除了,直接安装好后就可以使用了。

[tips]可以使用ubuntu中自带的 update-alternatives 命令来方便的进行多个gcc版本之间的切换(具体命令使用可以在google上搜)。

接下来就是使用gcc 4.1.2来编译sfslite,首先下载sfslite-0.8.16的tar包。(不要使用sfslite-0.8.17,编译会出错)

然后解压,进入源文件根目录,输入 ./configure –with-sfsmisc (with前是两个-) 只要这一个选项就可以了,不用输–with-dmalloc

接下来如果直接make的话会出错,会提示 unknown sizeof  ucred 。在网上找了很久,终于发现只有在编译时加上-D_GNU_SOURCE才可以。在gcc编译选项中增加 -D_GNU_SOURCE,这需要改makefile文件。具体为async和arpc目录下的Makefile文件中找到“ECFLAGS =” 改为:“ECFLAGS = -D_GNU_SOURCE”

然后编译安装即可。

C++静态工厂模式(采用shared_ptr)

C/C++ 3 Comments »

    今天介绍另一个比较常用的设计模式:工厂模式。工厂模式是指通过声明一个工厂的接口,然后定义该接口的各个实现类来具体实现不同的工厂。这里不打算写这种一般的方式,而只是写一种简单的工厂模式:静态工厂模式。这种模式的扩展性不如一般工厂模式那么好,但对于我们一般的应用已经足够了(而且系统设计的太复杂也不是好事,呵呵),静态工厂在实际中还是很常用的。

    值得说明的是这次没有像一般工厂模式那样采用普通的指针,而是采用之前介绍的shared_ptr,这是因为采用智能指针就不必担心工厂中创建的对象的释放问题,因为智能指针会帮你做好这一切,^_^

       下面是示例代码,代码中每个类按照不同文件进行放置,这样也可以了解工厂模式的一个好处,减小使用者和创建的产品类之间的依赖关系,这会在后面说明。

FileName: product.h

#ifndef _PRODUCT_H_
#define _PRODUCT_H_

class Product{
 public:
  virtual void myFunc()=0;
};

#endif

FileName: product_one.h

#ifndef _PRODUCT_ONE_H_
#define _PRODUCT_ONE_H_

#include "product.h"

class ProductOne:public Product{
 public:
  ProductOne();
  ~ProductOne();
  void myFunc();
};
#endif

FileName: product_one.cpp

#include "product_one.h"
#include <iostream>

using namespace std;

ProductOne::ProductOne(){
 cout<<"product one: i have been builded."<<endl;
}

ProductOne::~ProductOne(){
  cout<<"Product one: i have been destroyed."<<endl;

}
void ProductOne::myFunc(){
 cout<<"product one myFunc done!"<<endl;
}

FileName: product_two.h

#ifndef _PRODUCT_TWO_H_
#define _PRODUCT_TWO_H_

#include "product.h"

class ProductTwo:public Product{
 public:
  ProductTwo();
  ~ProductTwo();
  void myFunc();
};

#endif

FileName: product_two.cpp

#include "product_two.h"
#include <iostream>

using namespace std;

ProductTwo::ProductTwo(){
 cout<<"product two: i have been builded."<<endl;
}

ProductTwo::~ProductTwo(){
  cout<<"Product two: i have been destroyed."<<endl;
}

void ProductTwo::myFunc(){
 cout<<"product two myFunc done!"<<endl;
}

FileName: product_factory.h

#ifndef _PRODUCT_FACTORY_H_
#define _PRODUCT_FACTORY_H_

#include "product.h"
#include <tr1/memory>
#include <string>

class ProductFactory{
 public:
  static  std::tr1::shared_ptr<Product>  createProduct(std::string productDescript);
};

#endif

FileName: product_factory.cpp

#include "product_factory.h"
#include "product_one.h"
#include "product_two.h"

using namespace std;
using namespace std::tr1;

shared_ptr<Product> ProductFactory::createProduct(string productDescription){

 if(productDescription=="one"){
  shared_ptr<Product> productOne(new ProductOne());
  return productOne; 
  //you can also do like below.
  //return shared_ptr<Product> (new ProductOne());
 }
 else if(productDescription=="two"){
  shared_ptr<Product> productTwo(new ProductTwo());
  return productTwo; 
  //you can also do like below.
  //return shared_ptr<Product> (new ProductTwo());
 }
}

FileName: test_factory.cpp

#include "product.h"
#include "product_factory.h"
#include <string>
#include <iostream>
#include <tr1/memory>

using namespace std;
using namespace std::tr1;

int main(){
 cout<<"test 1 start..."<<endl;
 shared_ptr<Product> myProduct=ProductFactory::createProduct("one");

 myProduct->myFunc();

 cout<<endl<<"test 2 start..."<<endl;
 myProduct=ProductFactory::createProduct("two");
 myProduct->myFunc();
 { 
  cout<<endl<<"test 3 start..."<<endl;
  shared_ptr<Product> myProduct2=ProductFactory::createProduct("one");
  myProduct2->myFunc(); 
 }
 cout<<"all test done."<<endl<<endl;;
}

编译然后运行:

# g++ -o test_factory  test_factory.cpp  product_one.cpp  product_two.cpp  product_factory.cpp
# ./test_factory

运行结果如下:

test 1 start...
product one: i have been builded.
product one myFunc done!

test 2 start...
product two: i have been builded.
Product one: i have been destroyed.
product two myFunc done!

test 3 start...
product one: i have been builded.
product one myFunc done!
Product one: i have been destroyed.
all test done.

Product two: i have been destroyed.

    从上面结果可以看出通过使用工厂模式,可以使实例对象的生成由工厂来完成,减小使用者test_factory与实例产品product_one、product_two的依赖,这样也有利于后续程序的维护,即使product_one后来取消了,改动的代码也不会很大。大家看下test_factory.cpp的包含文件可以看出使用者不需要知道实际的产品子类(不直接知道),减小了编译的依赖。

    通过采用shared_ptr智能指针,可以避免使用者忘记释放掉new产生的实例类。这也使得代码更加安全,不容易造成内存泄露,也更容易编写异常安全或异常中立的代码。

   [题外话]也可以看出shared_ptr对于继承派生有很好的支持,^_^

单件模式的C++示例

C/C++ No Comments »

     之前花过一段时间学习设计模式,现在对于很多模式只留下一些感性的认识了。最常用的设计模式是策略模式 、工厂模式;最有用的设计原则是封装、组合>继承。
      以前的项目中大家为了简化往往忽视了设计模式的存在,这往往造成了项目维护的困难。现在又要进行新的代码编写了,希望能在设计之初考虑到这些问题,也方便以后代码维护的人。
      今天我记录一个简单的模式:单件模式。单件,毫无疑问就是独一无二的对象,其实在程序中这种对象有很多,例如存储系统配置信息的对象、接受和发送socket或是其他消息的对象、存储一些全局信息的对象,这些对象在系统中都是唯一的,它们建立好之后将不会销毁,直到程序终止(当然独一无二不意味着不销毁)。
      下面还是用代码说话把,下面代码位于三个文件中,分别为:configurator.h(Configurator类的定义头文件)、configurator.cpp(Configurator类的方法实现文件)、test_singleton.cpp(测试文件)。在C++中文件的划分是很重要的,这在大型程序中尤其如此,关于头文件的定义大家可以参考C++ Prime,上面讲的还是挺好的。(曾经又一次错误的在头文件中写下了using namespace std;结果导致各种莫名奇妙的编译错误,汗啊~)

FileName: configurator.h

#ifndef _CONFIGURATOR_H_
#define _CONFIGURATOR_H_

//this class has only one instance.
class Configurator{
	public:
		static Configurator* only();

		void setFlag(int newFlag);
		int getFlag();

		//NOT IMPLEMENTED ,AVOID MISUSE.
		Configurator(const Configurator&);
		Configurator& operator=(Configurator);
	private:
		//if it  has child class, the Constructor should be protected.
		Configurator();

		static Configurator* instance;

		int flag;
};
#endif

FileName: configurator.cpp

#include <iostream>
#include "configurator.h"

using namespace std;

Configurator* Configurator::instance=NULL;

Configurator::Configurator():flag(2){
 cout<<"I have been builded."<<endl;
}

Configurator*  Configurator::only(){
//if you want destory the class after use,you can do define instance here

//static Confiugrator * instance=NULL;

 if(instance==NULL){
  instance= new Configurator;
 }
 return instance;
}

void Configurator::setFlag(int newFlag){ 
 flag = newFlag;
}

int Configurator::getFlag(){ 
 return flag;
}

FileName: test_singleton.cpp

#include <iostream>
#include "configurator.h"

using namespace std;

int main(){

 cout<<"start building Configurator."<<endl;
 Configurator* first = Configurator::only();
 cout<<"first: flag is:"<<first->getFlag()<<endl;
 first->setFlag(7);
 cout<<"first: flag is:"<<first->getFlag()<<endl;

 //the other block.
 {
  Configurator* second=Configurator::only();
  cout<<"second: flag is:"<<second->getFlag()<<endl;
  second->setFlag(9);
  cout<<"second: flag is:"<<second->getFlag()<<endl;
 }

 cout<<"now first: flag is:"<<first->getFlag()<<endl;

}

编译并运行:

 # g++ configurator.cpp test_singleton.cpp
 # ./a.out

代码的运行结果如下:

start building Configurator.
I have been builded.
first: flag is:2
first: flag is:7
second: flag is:7
second: flag is:9
now first: flag is:9

从Configurator类的定义中可以看出它和普通类的定义所不同的有以下几点:

    1 、构造函数被定义为private,(如果有子类可以定义为protected),即对于外界不能通过构造函数来得到实例类型。如果你试图定义一个Configurator myCfg;编译时就会报错;获得实例变量的唯一办法就是调用only类方法,这也就保证了类的唯一性。

      [题外话]调用类的默认构造方法时应该写成Configurator myCfg; 而不是 Configurator myCfg();因为后者编译器会认为是方法的定义。

      2、为了进一步保证类的唯一性,在定义中把“构造拷贝函数”、“赋值函数”只进行声明而没有定义,这样可以防止某些人拷贝此单件类。如果试图拷贝的话可以通过编译,但链接时会报错(因为找不到对应的方法)。

       3、单件类包含有一个private的指向自己类型的指针,并且此指针定义成static类型,即全局的指针,可以用于指向此单件对象,并保证此对象的唯一性。

       众所周知,C++是支持全局变量的(当然也可以是全局的类变量),但是全局变量的出现使得程序文件中充斥了extern等字样,很多人提倡取消全局变量,它有很多缺点,其中包括降低代码的可读性,增加代码的维护难度,但全局方法有一个很大的优点:简单。不过我们还是应该尽量不用全局变量,相比而言,单件模式就是一个很好的解决方案,它可以让代码更易与维护并且避免一些不必要的错误。

      [题外话]很多事情存在都有它存在的理由,在实际中我们需要进行权衡,我们选择的不一定是最好的,但一定应该是最适合自己的。

[转]推荐视频:大自然中的数学

BrainStorm 2 Comments »

时常感叹,造物者一定是一个数学家,能把数学之美如此完美地融入自然界。
国外网友制作的这个短片向大家展示了大自然中令人震撼的数学之美,非常漂亮,值得一看:

YouTube 链接:http://www.youtube.com/watch?v=kkGeOWYOFoA

本文转自matrix67.com,原文地址:http://www.matrix67.com/blog/archives/3004

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS 登录