
暂无个人介绍
本文:说明提供了操作系统日期变更对数据库、应用程序数据和作业的影响。 1。它将会影响插入的任何记录,如果涉及到sysdate,则更改日期。 2。它还会影响在那个日期运行的任何调度器作业。 如果将系统时间向前调整,那么无论调整多长的时间都不会造成系统的重启。但是如果将系统时间向后调整,就会造成整个节点的重启. 正确的方法是首先关闭数据库和CLUSTER环境,然后修改系统时间,为了避免数据库中的时间出现冲突,最好等待当前时间超过修改前的系统时间后,再启动CLUSTER环境和RAC数据库. 请按照以下步骤: 1.进行备份 2.关闭数据库(清洁) 3.改变日期/时间操作系统 4.启动数据库 补充: 1.1、只修改日期,不修改时间,输入: date -s 2018-08-03 1.2、只修改时间,输入: date -s 14:15:00 1.3、同时修改日期时间,注意要加双引号,日期与时间之间有一空格,输入: date -s "2018-08-03 14:15:00" 2. 把系统时间写入CMOS clock -w 参考:What is the Impact on the Database When Modifying the OS Date? (文档 ID 559660.1) 本文转自 张冲andy 博客园博客,原文链接: http://www.cnblogs.com/andy6/p/8565559.html ,如需转载请自行联系原作者
1 2 3 4 5 一、Bash脚本编程风格 二、Bash条件测试: 三、脚本的状态返回值 四、练习脚本: 五、if 语句 一、Bash脚本编程风格 脚本格式: #!/bin/bash #description: say hello #version 0.0.1 //注释信息 #author:xiaoming //代码注释 #date:2017-01-01 缩进:适度添加空白行; 语法:编程语法格式、库调用(类库)、算法、数据结构 编程思想: 问题空间-->解空间 变量: 局部变量:当前shell 本地变量:local,函数内部 环境变量:当前shell及其子进程 位置参数变量:$1,$2,$3 特殊变量:$#,$@ 变量的数据类型://弱类型,默认都为字符型 字符型 数值型 算数运算:+,-,*,/,%,** expr,let let VAR=expression $((expression)) $[expression] var=$(expr argu1 + argu2) //一个小括号,命令引用 注意:有些时候,乘法符号需要转义 animal=dog;echo "${animal}s" //用花括号分开即可 PATH=“$PATH:/usr/locale/apache/bin" //引用原有的值,然后重新赋值 增强型赋值:变量做某种算术运算后回至此变量中 declare -i a=1 // i=$[$i+1] let i+=2 //这样也可以的:增强型复制机制 let +=,-=,*=,/=,%= //一般使用let进行 let ++,-- //自己加上/减去 1 let var=$[$var+1] let var+=1 let var++ 脚本1:添加user1 #!/bin/bash # first_scrpit id user1 &> /dev/null || useradd user1 id user2 &> /dev/null || useradd user2 user_id1=$(id -u user1) user_id2=$(id -u user2) id_sum=$[$user_id1+$user_id2] echo "sum is :$id_sum" 练习: 1.写一个脚本,计算/etc/passwd文件中第10个用户和第20个用户的id号之和 2.计算/etc/rc.d/init.d/functions和/etc/inittba文件的空白行数之和 1. id1=$(head -10 /etc/passwd | tail -1 | cut -d: -f3} id2=$(head -20 /etc/passwd | tail -1 | cut -d: -f3} 2. b1=$(grep "^$" /etc/rc.d/init.d/functions | wc -l) b1=$(grep "^[[:space:]]*$" /etc/rc.d/init.d/functions | wc -l) 二、Bash条件测试: 判断某需求是否满足,需要测试机制来实现 ||,&&,! //或,非,与 测试方法: 1.执行命令,并利用命令状态返回值来判断 0:成功 1-255:失败 echo $? 2.测试表达式 test -[d,e,f,h,p,r,s,S,w,N] a.txt d目录,f普通文件,e存在,h|-L符号文件, r可读,w可写,-s非空,-S套接字,-N上次读取之后修改过 [ expression ] ` expression ` 注意:expression两端必须有空格,否则为语法错误 bash测试类型: 数值测试 字符串测试 文件测试 1.数值测试:数值比较 -eq,-gt,-lt -ge,-le,-ne test 3 -gt 4 && echo True || echo false 2.字符串测试:根据ascii表,尽可能定义在` `中 == 是否相当 > 《 != 是否不等于 =- :左侧的字符串是否能够被右侧的pattern匹配 name=tom; [[ "$name" =~ t ]] ;echo $? //tom是否包含 t字母 //单目 -z “STRING” 判断子串是否为空,空则为真,否则为假 -n “STRING” 是否不空 [ -n "$name" ];echo $? 注意:[[ “a” > “b” ]] ;echo $? //一定要使用两个中括号,否则会出错 (1)字符串要加引用 (2)要使用` ` 3.文件测试 d目录,-S套接字,-p 管道文件 f普通文件, a|e存在, h|-L符号文件, -b 块设备文件 -s非空, -N上次读取之后修改过 //上次读取后,是否被修改过 4.文件权限测试: r可读,是否存在且对当前用户可读 w可写, x可执行 -g 是否存在,并且拥有sgid权限 -u 是否存在,并且拥有suid权限 -k sticky权限 [ -u /bin/passwd ] ; echo $? 5.从属关系测试 -O FILE 当前用户是否为文件的属主 -G FILE 当前用户是否为屋内安的属组 6.双目运算 FILE1 -ef FILE2 //file1与file2是否指向同一个fs的相同inode file1 -nt filr2 //file1是否新于file2 file1 -ot file2 //file1是否旧于file2 7.组合测试: 逻辑运算: 第一种方式: a && b a || b ! a //取反 [ -O file ] && [ -r file ] //当前用户为属主并且可读 [ -O file -a -x file ] expression -a expression2 // expression -o expression2 ! expression test "a" != "$HOME" -a 3 -ge 4 ; echo $? [ ! \( "a" = "$HOME" -o 3 -lt 4 \) ]; echo $? [ ! \( "a" = "$HOME" -o '(' 3 -lt 4 ')' ")" ]; echo $? 三、脚本的状态返回值 默认是脚本中执行的最后一条命令的状态返回值 自定义状态返回值 exit [n] //自定义状态返回值,状态码 注意:shell进程遇到exit会终止,因此整个脚本将会结束 一般判断条件是否满足,再执行exit 注意:XShell的锁定和接触锁定 vim ctrl + s 锁定后, ctrl + q 取消锁定 四、练习脚本: 脚本1: 将当前主机名称保存至hostName变量中: 主机名为空,或者为localhost.localdomain,则将其设置为www.mt.com #!/bin/bash hostName=$(hostname) [ -z "$hostName" -o "$hostName"=="localhost.localdomain" -o hostName=="localhost" ] && hostname www.xt.com 注意: //必须是 [] ,而不能是 ` ` ,或者 //== 前后不需要空格 // [ ] 前后都需要空格, //$hostname 得需要“ ” //[ ** -o|-a| ** ] 判断内部 // && || ! 判断[]外部 脚本2.向脚本传递参数 位置参数变量; 引用: $1,$2,...$(12) shift 轮替 shift n :位置参数变量 特殊变量: $0:脚本文件名 $#: 获取参数个数总和 $*: 所有参数 $@: 所有参数 引用变量计算数值 bash sum.sh 23 78 #!/bin/bash # echo $[$1 + $2] //判断文件空白行行数 #!/bin/bash [ $# -lt 2 ] && echo "At least two files" && exit 1 b1=$(grep "^$" $1 | wc -l) b2=$(grep "^$" $2 | wc -l) echo "sum of blank is : $[b1+b2]"五、if 语句 过程式编程语言的代码执行顺序 顺序执行:逐条执行 选择执行: 代码有一个分支:条件满足则执行 两个以上的分支:只会执行其中一个满足条件的执行 循环执行: 代码片段(循环体)要执行0,1或多个来回 选择执行: if 测试条件 ; then //需要分号 代码分支 fi if 测试条件 //then单独分行,不需要分号 then 代码分支 fi 双分支if语句 if 测试条件; then 条件为真时运行 else 条件为假时执行 fi 脚本3:通过参数传递一个用户名给脚本,此用户不存在时添加该用户 #!/bin/bash if [ $# -lt 1 ]; then echo "At least one user_name" exit 1 fi if ! [ grep "$1\>" /etc/passwd ] &> /dev/null; then useradd $1 echo $1 | passwd --stdin $1 echo "USER $1 added succeed!" exit 0 else echo "Failure ..." exit1 fi 脚本4:通过键盘给定两个数字,输出其中较大的值 #!/bin/bash # if [ $# -lt 2 ] ; then echo "Two intergers." exit 2 fi if [ $1 -ge $2 ] ;then echo "max number is: $1" else echo "max number is: $2" fi 脚本5:通过命令参数传递给定两个文件名,如果某文件不存在,则结束脚本 返回每个文件的行数,并说明其中行数最多的文件 [root@wolf test]# cat 2.sh #!/bin/bash #AUthor xt #date 2017-07-22 declare -i f1 f2 if [ $# -lt 2 ] ; then echo "At least two files " exit 1 ; fi #if [ ! -f $1 ] || [ ! -f $2 ] ; then if ! [ -f $1 -a -f $2 ] ; then echo "At least one is not a primary file" exit 2 ; else f1=$(wc -l $1 | cut -d' ' -f1) f2=$(wc -l $2 | cut -d' ' -f1) if [ $f1 -gt $f2 ] ;then max=$f1 else max=$f2 fi echo "First file's line is $f1" echo "Second file's line is $f2" echo "Max is line is $max" fi 本文转自MT_IT51CTO博客,原文链接:http://blog.51cto.com/hmtk520/1950102,如需转载请自行联系原作者
题目1: // // main.cpp // 2013-7-17作业1 // // Created by 丁小未 on 13-7-17. // Copyright (c) 2013年 dingxiaowei. All rights reserved. // //1.有这样一个学生系统,用于学校存储学生信息,当有新生的时候存储新生信息,有学生毕业的时候删除学生信息,还可以修改学生信息,比如学生突然更改了姓名或者学生换了专业。学生信息至少要有姓名,学号,年龄,性别,专业,手机号码。 //条件:使用类Student,完成。 #include <iostream> #define NUM 50 using namespace std; class Student { private: int num;//学号 string name;//姓名 int age; //年龄 char sex; //性别 string profession;//专业 string telphone; public: Student() { } Student(int nu,string na,int ag,char sx,string pr,string te) { num = nu; name = na; age = ag; sex = sx; profession = pr; telphone = te; } void SetNum(int nu) { num = nu; } void SetName(string na) { name = na; } void SetAge(int ag) { age = ag; } void SetSex(char sx) { sex = sx; } void SetProfession(string pr) { profession = pr; } void SetTelphone(string te) { telphone = te; } Student* GetStudent() { Student *stu; return stu; } int GetNum() { return num; } string GetName() { return name; } int GetAge() { return age; } char GetSex() { return sex; } string GetProfession() { return profession; } string GetTelphone() { return telphone; } //还要有整体的赋值,可以用单目运算符重写= Student&operator = (const Student & other) { if (this == &other) { return *this; } this->num = other.num; this->name = other.name; this->age = other.age; this->sex = other.sex; this->profession = other.profession; this->telphone = other.telphone; } }; //输入学生,返回输入的个数 int setStudent(Student stu[],int n) { int i=0; int j; int iTemp; string sTemp; char cTemp; int f=0; do { cout<<"请输入学生学号"<<endl; cin>>iTemp; stu[i].SetNum(iTemp); cout<<"请输入学生姓名"<<endl; cin>>sTemp; stu[i].SetName(sTemp); cout<<"请输入学生年龄"<<endl; cin>>iTemp; stu[i].SetAge(iTemp); cout<<"请输入学生性别"<<endl; cin>>cTemp; stu[i].SetSex(cTemp); cout<<"请输入学生专业"<<endl; cin>>sTemp; stu[i].SetProfession(sTemp); cout<<"请输入学生手机号"<<endl; cin>>sTemp; stu[i].SetTelphone(sTemp); i++; cout<<"请问要输入学生信息吗?(1.要 2.不要)"; cin>>f; } while (1==f); // for (i=0; i<n; i++) { // printf("请问要输入学生信息吗?(1.要 2.不要)"); // cin>>j; // if (2==j) { // break; // } // else // { // cout<<"请输入学生学号"<<endl; // cin>>iTemp; // stu[i].SetNum(iTemp); // cout<<"请输入学生姓名"<<endl; // cin>>sTemp; // stu[i].SetName(sTemp); // cout<<"请输入学生年龄"<<endl; // cin>>iTemp; // stu[i].SetAge(iTemp); // cout<<"请输入学生性别"<<endl; // cin>>cTemp; // stu[i].SetSex(cTemp); // cout<<"请输入学生专业"<<endl; // cin>>sTemp; // stu[i].SetProfession(sTemp); // cout<<"请输入学生手机号"<<endl; // cin>>sTemp; // stu[i].SetTelphone(sTemp); // } // } return i;//返回输入的学生数 } //返回查找学号为什么的学生的下标 int findStudent(Student *stu,int n,int findNum)//要查询的Student数组,实际查询的条数,要查询的学号 { int i; int m=-1; for (i=0; i<n; i++) { if(stu[i].GetNum()==findNum) { m=i; break; } } return m; //返回Stu的下标 } //删除一条学生信息 int deleteStudent(Student *stu,int n,int deleteStudentNum) //在学生数组中删除学号为deleteStudentNum的学生,并且个数减少1 { int i; int j=0; for (i=0; i<n; i++) { if (stu[i].GetNum()==deleteStudentNum) { for (j=i; j<n-1; j++) { stu[j]=stu[j+1]; } n--; i--; } } return n; //返回n-1 } Student addStudent() { Student stu; int iTemp; char cTemp; string sTemp; cout<<"请输入学生学号"<<endl; cin>>iTemp; stu.SetNum(iTemp); cout<<"请输入学生姓名"<<endl; cin>>sTemp; stu.SetName(sTemp); cout<<"请输入学生年龄"<<endl; cin>>iTemp; stu.SetAge(iTemp); cout<<"请输入学生性别"<<endl; cin>>cTemp; stu.SetSex(cTemp); cout<<"请输入学生专业"<<endl; cin>>sTemp; stu.SetProfession(sTemp); cout<<"请输入学生手机号"<<endl; cin>>sTemp; stu.SetTelphone(sTemp); return stu; } //添加一个学生(可能有点问题) int insertStudent(Student *stu,int n) { Student s=addStudent(); stu[n] = s; return ++n; } //修改学生信息 void alterStudent() { } //打印标题行 void printTitle() { cout<<"学号 "<<"姓名 "<<"年龄 "<<"性别 "<<"专业 "<<"手机号"<<endl; } //输出打印学生信息 void getStudent(Student *stu,int n) { int i; printTitle();//打印标题 for (i=0; i<n; i++) { cout<<stu[i].GetNum()<<" "<<stu[i].GetName()<<" "<<stu[i].GetAge()<<" "<<stu[i].GetSex()<<" "<<stu[i].GetProfession()<<" "<<stu[i].GetTelphone()<<" "<<endl; } } //显示菜单 void showMenu() { cout<<">>>>>>>>>>>>欢迎使用学生信息管理系统<<<<<<<<<<<<<<<"<<endl; cout<<"***********************************************"<<endl; cout<<"* 1.初始化学生 2.添加学生 *"<<endl; cout<<"* 3.修改学生 4.删除学生 *"<<endl; cout<<"* 5.显示所有学生 6.退出 *"<<endl; cout<<"***********************************************"<<endl; } //菜单选择 int get_menu_choice() { int menu_ch; do { cout<<"选择菜单选项:"; cin>>menu_ch; if ((menu_ch<0)||(menu_ch>6)) { cout<<"error!"<<endl; } } while ((menu_ch<0)||(menu_ch>6)); return menu_ch; } int main(int argc, const char * argv[]) { Student* stu = new Student[NUM]; int r1=0; int r2;//保存查找的学号 int choose; while (1) { showMenu(); switch (get_menu_choice()) { case 1: r1=setStudent(stu,NUM);//返回输入的个数 break; case 2: r1=insertStudent(stu,r1); getStudent(stu, r1); break; case 3: cout<<"请输入要修改的学生的学号:"; int nn; cin>>nn; r2=findStudent(stu, r1, nn); if (r2==-1) { cout<<"没有该学生!"; } else { int iTemp; char cTemp; string sTemp; cout<<"请输入学生学号"<<endl; cin>>iTemp; stu[r2].SetNum(iTemp); cout<<"请输入学生姓名"<<endl; cin>>sTemp; stu[r2].SetName(sTemp); cout<<"请输入学生年龄"<<endl; cin>>iTemp; stu[r2].SetAge(iTemp); cout<<"请输入学生性别"<<endl; cin>>cTemp; stu[r2].SetSex(cTemp); cout<<"请输入学生专业"<<endl; cin>>sTemp; stu[r2].SetProfession(sTemp); cout<<"请输入学生手机号"<<endl; cin>>sTemp; stu[r2].SetTelphone(sTemp); } break; case 4: cout<<"请输入要删除学生的学号:"; int n; cin>>n; r2=findStudent(stu, r1, n); if (r2==-1) { cout<<"没有该学生!"; } else { r1=deleteStudent(stu, r1, n); cout<<"删除成功!"<<"\n"<<"显示所有学生"<<endl; getStudent(stu, r1); } break; case 5: getStudent(stu, r1); break; case 6: cout<<"您已经成功退出系统,欢迎再次使用!谢谢!"<<endl; break; default: break; } } return 0; } 结果: //题目2.在一个程序中,各写出重载覆盖隐藏的成员函数 #include <iostream> using namespace std; class A { public: void func() { cout<<"A的func()"<<endl; } void func1(int i) { cout<<"A的func1()"<<" 参数是:"<<i<<endl; } virtual void func2() { cout<<"A的func2()"<<endl; } virtual void func2(int i) { cout<<"A的func2()"<<" 参数是:"<<i<<endl; } }; class B:public A { public: void func() //基类没有virtual关键字就是表示基类被隐藏 { cout<<"B的func()"<<endl; } void func2() //基类有virtual关键字就表示基类方法被覆盖 { cout<<"B的func2()"<<endl; } void func2(int i) { cout<<"B的func2()"<<" 参数:"<<i<<endl; } }; int main(int argc, const char * argv[]) { A a1; A *a2=&a1; B b1; A *a3=&b1; B *b2=&b1; a1.func(); //A的func() a1.func1(1); //A的func1() 1 a2->func1(2); //A的func1() 2 a2->func2(3); //A的func2() 3 a2->func(); //A的func() a3->func(); //A的func() a3->func1(4); //A的func1() 4 a3->func2(); //B的func2() a3->func2(5); //B的func2() 5 b1.func(); //B的func() b1.func2(); //B的func2() b2->func(); //B的func() b2->func2(); //B的func2() b2->func1(6); //A的func1() 6 b2->A::func2(7); //A的func2() 7 return 0; } 结果: A的func() A的func1() 参数是:1 A的func1() 参数是:2 A的func2() 参数是:3 A的func() A的func() A的func1() 参数是:4 B的func2() B的func2() 参数:5 B的func() B的func2() B的func() B的func2() A的func1() 参数是:6 A的func2() 参数是:7 作业3: #include <iostream> using namespace std; class A { public: A() { cout<<"A\n"; } virtual void func() { cout<<"A::func\n"; } virtual void func1() { cout<<"A::func1\n"; } }; class B : public A { public: B() { cout<<"B\n"; func(); } void func1() { cout<<"B::func\n"; } }; int main(void ) { A *a = new B(); //先创建B对象,又因为B是继承的A,所以在构造B之前要先构造A,所以输出A,然后构造B,输出B,然后调用func(),输出A::func\n a->func(); //由于a中的func()方法虽然定义的是虚函数,但是由于B类中没有该重名函数,所以直接调用A中的func方法,输出A::func a->func1(); //由于A中的func1方法是虚函数,且B中也有该方法,所以就调用B中的func1方法,输出B::func\n B b; //实例化一个B对象,先实例化他的基类,调用A的构造方法,打印输出A,然后在调用B的构造方法,打印输出B,在调用A中的func方法,打印输出A::func\n b.func(); //调用继承自A中的func方法 } 结果: A B A::func A::func B::func A B A::func A::func 本文转自蓬莱仙羽51CTO博客,原文链接:http://blog.51cto.com/dingxiaowei/1366449,如需转载请自行联系原作者
本文出自Simmy的个人blog:西米在线 http://simmyonline.com/archives/391.html 症状:开机时自动打开我的文档。 原因:中病毒,修改了注册表项。 解决方法:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit,键值显示为:C:\WINDOWS\system32\userinit.exe,EXPLORER 将EXPLORER删去。 本文转simmy51CTO博客,原文链接:http://blog.51cto.com/helpdesk/174584,如需转载请自行联系原作者
本文出自Simmy的个人blog:西米在线 http://simmyonline.com/archives/403.html 症状:打开Lotus Notes时收到错误信息: Notes Directory inaccessible 原因:权限导致 解决方法:google了一下,到了IBM Lotus的官方KB,看了几条,大部分说是admin权限的原因。于是把Notes文件夹赋予user完全控制的权限,再试,打开了。 本文转simmy51CTO博客,原文链接:http://blog.51cto.com/helpdesk/175330,如需转载请自行联系原作者
本文出自Simmy的个人blog:西米在线 http://simmyonline.com/archives/464.html 作为IT Helpdesk,每天的工作基本上都是remote到用户的机上帮用户解决各类电脑问题,因此远程维护软件是我的绝佳帮手。一直以来使用的远程连接方式主要有3种。 1. VNC VNC是一款免费的远程连接的软件,我问了几位IT友人,不少大公司都采用,我们也是,虽然功能简单了点,不过简单实用。安装好后,开机时会自动启动,把鼠标放到VNC的图标上就会弹出IP地址,通过这个地址就可连接上用户端。 VNC还有个实用的方式,就是让用户端连上来,这对被防火墙阻挡而无法连上用户端的情况很适用。本机先启动Run Listening VNC Viewer 用户端右键单击VNC图标,选择Add New Client,在弹出框中输入本机的IP地址,然后本机便会自动弹出用户机的界面出来。 2.Windows 远程桌面 不用多说了,不方便的地方是连接时会注销掉当前用户,不过优点是支持远程视频及声音。 3.Netmeeting 运行--conf--第一次用要填一堆东西。完成后弹出如此界面。 双方均启动netmeeting,在电话旁的空白栏输入一方的IP,然后点电话进行呼叫。对方点接受即开始会议。 连接后会弹出用户信息,点击共享程序--桌面--共享,把允许控制也点上。对方即可看到用户桌面。 要控制的话,点控制--请求控制,这边点接受即可。 本文转simmy51CTO博客,原文链接:http://blog.51cto.com/helpdesk/180927,如需转载请自行联系原作者
本文出自Simmy的个人blog:西米在线 http://simmyonline.com/archives/542.html The Enhanced Interior Gateway Routing Protocol (EIGRP) Stub Routing feature improves network stability, reduces resource utilization, and simplifies stub router configuration. Stub routing is commonly used in a hub and spoke network topology. In a hub and spoke network, one or more end (stub) networks are connected to a remote router (the spoke) that is connected to one or more distribution routers (the hub). The remote router is adjacent only to one or more distribution routers. The only route for IP traffic to follow into the remote router is through a distribution router. This type of configuration is commonly used in WAN topologies where the distribution router is directly connected to a WAN. The distribution router can be connected to many more remote routers. Often, the distribution router will be connected to 100 or more remote routers. In a hub and spoke topology, the remote router must forward all nonlocal traffic to a distribution router, so it becomes unnecessary for the remote router to hold a complete routing table. Generally, the distribution router need not send anything more than a default route to the remote router. When using the EIGRP Stub Routing feature, you need to configure the distribution and remote routers to use EIGRP, and to configure only the remote router as a stub. Only specified routes are propagated from the remote (stub) router. The router responds to queries for summaries, connected routes, redistributed static routes, external routes, and internal routes with the message "inaccessible." A router that is configured as a stub will send a special peer information packet to all neighboring routers to report its status as a stub router. 本文转simmy51CTO博客,原文链接:http://blog.51cto.com/helpdesk/187889,如需转载请自行联系原作者
本文出自Simmy的个人blog:西米在线 http://simmyonline.com/archives/544.html 症状:用户报告说Citrix登录后,打印PO时没有反应。 原因:不明。 解决方法:1.打印机属性--高级--选择“直接打印到打印机” 2. 重新安装Citrix客户端 本文转simmy51CTO博客,原文链接:http://blog.51cto.com/helpdesk/188184,如需转载请自行联系原作者
本文出自Simmy的个人blog:西米在线 http://simmyonline.com/archives/569.html 症状:打开已经映射好的网络盘时显示此错误信息 原因:默认保存的用户名及密码不对 解决方法:控制面板--用户帐户--高级--管理密码,把自动记住密码的账户删除 本文转simmy51CTO博客,原文链接:http://blog.51cto.com/helpdesk/193844,如需转载请自行联系原作者
用户教了我一招,如何去计算选定的数据的个数,如图: 选定要计算的单元格的数目--在状态栏上右键--计数,然后状态栏上就会显示合计数。 本文转simmy51CTO博客,原文链接:http://blog.51cto.com/helpdesk/211880,如需转载请自行联系原作者
很奇怪不知为什么Outlook2007设计的时候,竟然没有可以选择打印第几页的功能,有时用户只要打印第一页,或者其中某页的内容时,只能用copy的方式将其复制到word上面再打印,这的确很不方便。 公司后来自己写了个Add-in用于实现这一功能。而现在outlook2007 SP2带了这个功能,安装了SP2后,打印时就会多出如图所示选项: 这是在 Outlook2003的情况 我这个Outlook是在装office 2003时选上一起装的,而不是独立的outlook2003客户端。 本文转simmy51CTO博客,原文链接:http://blog.51cto.com/helpdesk/215007,如需转载请自行联系原作者
今天帮个用户转移archive文件时,由于误操作,将文件夹内的文件重复复制了一份,造成文件夹内的email变成有2份重复一样的。于是想到之前看过有删除重复邮件的软件,遂baidu之,一下就找到了。ODIR (Outlook Duplicate Items Remover 1.4.2),这是一款免费的软件,下载地址:http://www.vaita.com/ODIR.asp 安装完成后,在outlook菜单栏会多出一个选项:ODIR 点击后弹出界面,点Remove Duplicate Items 即可 这里有更详细的解决方法: http://fjqmj.blog.163.com/blog/static/8315534720099285481311/ 摘录: 我的Outlook里面也曾经存有大量的重复邮件,总共一万余封邮件中有超过1/3都是重复收取的。我分别试用了上述4款程序进行筛选,“ODIR”总是无法正常完成整个筛选过程,扫描了很少一部分邮件之后就通知我任务完成,我开始以为是系统有什么问题造成程序出错,但在另外一台电脑上测试也是同样的问题。“Duplicates Email Remover for Outlook”和“Duplicates Remover for Outlook”虽然扫描的效果很好,但是因为没有注册,所以无法达到清除重复邮件的目的。最后还是“RepMailDel”帮我彻底清除了所有的重复邮件。 本文转simmy51CTO博客,原文链接:http://blog.51cto.com/helpdesk/235238,如需转载请自行联系原作者
打印服务器系统是Windows 2000,装有几十部HP的打印机,不知从何时起,开始出现spoolsv服务会自动停止的情况,需要手动去重启,查了下资料,有说是关于:windows KB961371引起的,可我查了server 的update,已经是新版的KB961371-v2 关于此主题的讨论: http://social.technet.microsoft.com/Forums/zh-TW/winserverzhcht/thread/4f43e4bb-405e-4f8a-81d7-4e1cf06da227 左右也查不出原因,网上找了下,可用这个bat来自动检测并重启服务,默认检查时间为30秒,可按环境需求修改: :do tasklist|findstr /i "spoolsv.exe" ||start "" "C:\WINDOWS\system32\spoolsv.exe" ping 127.0.0.1 -n 30 >nul goto do 本文转simmy51CTO博客,原文链接:http://blog.51cto.com/helpdesk/240769,如需转载请自行联系原作者
这篇博文是我在2009-07-15 14:11:16时写的,以纪念我出来工作的3年岁月。5年,对一个国家来说,是一段规划期;3年,对一个人来说是一段成长期,3年时间足以让一个人了解很多,成长很多。看了博友:xueqinhe的《对工作的一点想法》http://xueqinhe.blog.51cto.com/110562/258433 使我萌生把我的3年也贴出来的想法,我与xueqinhe都是06界毕业生。转眼已3年,岁月匆匆,看着年华逝去,竟有丝丝XXYY的情怀...... 新一届的毕业生,正汹涌地奔向人才市场这个小海,而我在这个小海里已经畅游了3年。3年,说长不长,说短不短,不过我方才适应了在小海里游泳的感觉。工作3年了,小记一下,以示纪念。 从事技术支持工作已近3年,job title从技术员,技术支持,到现在的Helpdesk and Training Administrator。虽然不同公司对职位的叫法不同,但工作内容基本是一样的,只是应用环境不一样罢了。在这过程中我才明白,原来技术支持的核心是服务意识而非技术,真是后知后觉。 第一份工作在一家很小的系统集成提供商处工作,每天必须上门处理用户的故障请求,如电脑故障,打印机故障等;还要维护公司帮客户安装的一些系统,如门禁,考勤,视频监控等;再有时会被派去协助做些小工程,如网络布线,安装机柜,调试设备等;有时还兼送货服务,小公司分工没那么明确,都是相互协调,有空就上,这样虽然工作看起来有些繁杂,但对自己来说却能接触到更多不同的技术内容及学得更快。由于每天要在到不同地方处理故障,因此有不少时间是在车上度过的;每天的故障请求都很多,时间很紧,因此有时在某些故障上花的处理时间过多就会导致后面的故障单无法处理或者降低了响应时间,进而影响客户满意度,严重的话导致客户流失。因此,有时要学会按故障大小及客户大小来安排处理的进度,这种思维的养成对自己日后的工作大有裨益。工作的压力是可想而知的,可这一方面使自己的抗压能力提升了不少,处理起故障来不会再自乱阵脚。例如有时用户方面的故障很多,而自己的时间又有限,要在最短的时间内处理完大部分问题,这就要求有强的分析及解决问题的技巧。有时,用户报障说服务器挂掉了,工作无法进行,这对用户方来说是非常严重的事情,也是我们最担心的事情,这样的情况下只能静下心来分析,找到故障。布线的时候也会遇到同样的情况,例如由于客户方房屋结构的原因,会引起些预想不到的事情,这时要灵活处理,或改变线路,或穿墙走线。处理故障往往很难预料到在多长的时间内可以将其解决掉,而且有时用户还会有别的问题使你无法按时完成,这样的话,休息时间就很难安排,吃饭也常常难按时,长此以往我的胃也开始出现了一些问题。这份工作,我是非常用心做的,每天忙忙碌碌,虽然辛苦却也开心,毕竟是在做着自己喜欢做的事。不过后来,我觉得自己需要做些调整了,这样下去,没有什么前途可言。 第二份工作在一家港资工厂,工作相对轻松许多之所以选择做网管,是因为第一份工作太累了,在工作的过程中,对自己,对工作有了更多的悟解与发现。于是打算找份能有多点时间,能静下心来学习的工作。于是选择了网管。工厂的环境与公司的环境大有不同,虽然工厂比较封闭,但正因为如此,人更能静下心来。在人才市场找工作的过程中,我发觉很多大公司要求英文,于是我就想写份英文简历,可是想了半天也不知如何下笔,不知怎样用专业点的文字来表达自己的专业技能。当时我就发誓,一年后我一定要写出英文简历,当然一年后,我实现了。工作的这家工厂是HK一家上市集团的下属企业,因此厂里也住着几位老外,慢慢的在帮他们维护电脑的过程中,我跟他们都熟了,口语交流从害羞出口到侃侃而谈。在这个过程中,我也通过参加一些英语认证以考带学的方式来提高自己的英语水平,如BEC,PET4等。另外在这段时间我买了大量的书来看,以此提高自己。对于IT方面,我采取的也是这样的策略。通过努力,考取了网络工程师及MCSE的认证。这一年的时间,我过得很充实。一年后,我觉得是时候离开这里了。我把目标瞄准了外企,经过几轮面试后,我如愿以偿。 第三份工作,跨国外企,工作环境基本用的都是英文。之所以这样选择是因为外企的IT应用相对内资企业要先进很多的,另外我也想自己的职业素养能有所提高,而这些只有外企才能提供,我想学习如何工作。大公司的运转靠的是系统,做起事来很多流程,讲究合作,虽然有点麻烦,但是保证了它的安全性与稳定性。这里的IT应用真的非常复杂,就连内部的IT架构,目前我也还没完全弄清楚,工作细分的太厉害了。大公司,能学习的地方真的非常之多。今年的目标是拿下CCNP及ITIL Foundation,在技术上更深一层,然后就是多点了解IT应用与业务的关系。 人,年轻的时候总有许多的梦想。我的梦想很多,有时发发白日梦,自己也会笑起来。这样做起事来更有干劲。 本文转simmy51CTO博客,原文链接:http://blog.51cto.com/helpdesk/259081,如需转载请自行联系原作者
Ubuntu通过apt-get命令安装java jdk6 java 2009-12-25 11:20:45 阅读397 评论0 字号:大中小 其实Ubuntu要安装Jdk6是非常简单的,简单到你只要去新立得软件包管理器里搜索一下sun,然后勾上jdk,bin等几个软件,顺便也可以把之前安装的老版JDK删除掉。然后点击确定系统就自动给你安装好了! 也可以直接输入: sudo apt-get install sun-java6-jdk 命令来安装 装好后,输入命令 sudo update-alternatives --config java,然后从菜单里选择java-6-sun就可以了。 现在你可以输入java -version来测试你的Jdk是否安装好,怎么样,好了吧! 在我的机子上,只有java命令有效,其它的如javac,native2ascii等都找不到命令,说明默认只把java的链接添加到了$PATH中,这里我们可以有两种方法来解决。一是手动添加链接到/usr/bin目录下,二是把$JAVA_HOME/bin添加到$PATH变量中。 这里我采用第二种,使用你喜欢的编辑器,在~/.bashrc文件末尾加上以下两行: export JAVA_HOME=/usr/lib/jvm/java-6-sun export PATH=$PATH:$JAVA_HOME/bin 好,都OK了,重新打开一个终端,是不是一切都好了呢! 本文转hackfreer51CTO博客,原文链接:http://blog.51cto.com/pnig0s1992/440888,如需转载请自行联系原作者
v3rity是由David Litchfield在2010年3月 建立起来的组织,旨在解决一些IT问题。官方网站提供了一些比较有用的文章。 Papers on Oracle ForensicsOracle Forensics Part 7: Using the Oracle System Change Number in Forensic InvestigationsOracle Forensics Part 6: Examining Undo Segments, Flashback and the Oracle Recycle BinOracle Forensics Part 5: Finding Evidence in the Absence of AuditingOracle Forensics Part 4: Live ResponseOracle Forensics Part 3: Isolating Evidence of Attacks Against the Authentication MechanismOracle Forensics Part 2: Locating Dropped ObjectsOracle Forensics Part 1: Dissecting the Redo Logs Papers on Database SecurityHacking Aurora in Oracle 11gExploiting PL/SQL Injection With Only CREATE SESSION Privileges in Oracle 11g Understanding Database SecurityExploiting PL/SQL Injection Flaws with only CREATE SESSION PrivilegesBypassing DBMS_ASSERT (in certain situations)Lateral SQL Injection – A New Class of Vulnerability in Oracle.Cursor Injection – A New Method for Exploiting PL/SQL Injection and Potential DefencesCursor Snarfing – A New Class of Attack in OracleOracle PL/SQL Injection (Blackhat Japan)Threat Profiling Microsoft SQL ServerHack Proofing Oracle Application ServerMicrosoft SQL Server PasswordsData-mining with SQL Injection and InferenceDatabase Servers on Windows XP and the Unintended Consequences of Simple File SharingWeb Application Disassembly with ODBC Error MessagesHackproofing Lotus Domino Web Server Papers on Buffer OverflowsAn Introduction to Heap overflows on AIX 5.3LBuffer Underruns, DEP, ASLR and Improving the Exploitation Prevention Mechanisms (XPMs) on the Windows PlatformDefeating the Stack Based Buffer Overflow Prevention Mechanism of Microsoft Windows 2003 ServerVariations in Exploit methods between Linux and WindowsNon-stack Based Exploitation of Buffer Overrun Vulnerabilities on Windows NT/2000/XPWindows Heap OverflowsWindows 2000 Format String VulnerabilitiesBuffer Overflows on SPARC ArchitectureBuffer Overflows for BeginnersExploiting Windows NT 4.0 Buffer Overruns (A Case Study: RASMAN.EXE) 本文转hackfreer51CTO博客,原文链接:http://blog.51cto.com/pnig0s1992/573371,如需转载请自行联系原作者
Pnig0s p.s:将主进程的内核对象句柄通过CreateProcess的lpCmdLine参数传递给子进程,当然之前还要自定义一个SECURITY_ATTRIBUTES结构传递给创建内核对象的函数来将内核对象句柄设置为可继承的,然后在CreateProcess中将bInheritHandle置为TRUE使子进程可以将主进程的所有可继承的内核对象句柄复制到自己的内核对象句柄表中,从而实现不同进程间的内核对象的共享。小实践,网上代码资料比较少,贴出来方便大家吧 主进程: #include <Windows.h> #include <stdio.h> #define MAX_BUFFER_SIZE 4096 int main(int argc,char * argv[]){ HANDLE hFile; LPVOID lpFileBuffer; DWORD dwBytesInFile; int iResult; SECURITY_ATTRIBUTES sa; STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si,sizeof(si)); si.cb = sizeof(si); ZeroMemory(&pi,sizeof(pi)); sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; hFile = CreateFile("robots.txt",GENERIC_READ,FILE_SHARE_READ,&sa,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if(hFile == INVALID_HANDLE_VALUE){ printf("Create file handle failed.(%d)\n",GetLastError()); CloseHandle(hFile); return 1; } lpFileBuffer = HeapAlloc(GetProcessHeap(),0,MAX_BUFFER_SIZE); while(1){ iResult = ReadFile(hFile,lpFileBuffer,MAX_BUFFER_SIZE,&dwBytesInFile,NULL); if(!iResult){ printf("Read file failed.(%d)\n",GetLastError()); CloseHandle(hFile); return 1; } if(dwBytesInFile > MAX_BUFFER_SIZE){ HeapReAlloc(GetProcessHeap(),0,lpFileBuffer,dwBytesInFile); ZeroMemory(lpFileBuffer,dwBytesInFile); }else{ break; } } printf("Parent process id:%d\n",GetCurrentProcessId()); printf("[Parent]The value of the handle is %u\n",hFile); printf("[Parent]The index of the handle in table is:%u\n",((DWORD)hFile/4)); printf("[Parent]The content of the robots.txt:\n%s\n\n\n",lpFileBuffer); //最好将要传递给子进程参数命令行的值存放在缓存中 LPSTR lpCommandLine; //定义一个字符串指针以存放内核对象句柄 lpCommandLine = (LPSTR)HeapAlloc(GetProcessHeap(),0,1024); //为字符串指针分配内存 ltoa((DWORD)hFile,lpCommandLine,10); //将HANDLE句柄转换为字符串类型储存 if(!CreateProcess("ChildProcess.exe",lpCommandLine,NULL,NULL,TRUE,0,NULL,NULL,&si,&pi)){ printf("Create child process failed.(%d)\n",GetLastError()); return 1; } printf("Child process created.\n\n\n"); CloseHandle(hFile); WaitForSingleObject(pi.hProcess,INFINITE); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); system("pause"); return 0; } 子进程: #include <Windows.h> #include <stdio.h> #define MAX_BUFFER_SIZE 1024 int main(int argc,char * argv[]){ int iResult; LPSTR lpFileBuffer; DWORD dwBytesHasRead; LPSTR commandLine = GetCommandLine(); HANDLE hChildFile = (HANDLE)atol(commandLine); lpFileBuffer = (LPSTR)HeapAlloc(GetProcessHeap(),0,MAX_BUFFER_SIZE); SetFilePointer(hChildFile,NULL,NULL,FILE_BEGIN); iResult = ReadFile(hChildFile,lpFileBuffer,MAX_BUFFER_SIZE,&dwBytesHasRead,NULL); if(!iResult){ printf("Read file failed.(%d)\n",GetLastError()); CloseHandle(hChildFile); return 1; } printf("Child process id:%d\n",GetCurrentProcessId()); printf("[Child]The value of the handle is %u\n",(DWORD)hChildFile); printf("[Child]The index of the handle in table is:%u\n",((DWORD)hChildFile/4)); printf("[Child]The content of the robots.txt:\n%s\n\n\n",lpFileBuffer); CloseHandle(hChildFile); return 0; } 运行结果: 本文转hackfreer51CTO博客,原文链接:http://blog.51cto.com/pnig0s1992/685867,如需转载请自行联系原作者
2007-07 开始用 TiddlyWiki 制作每周的会议记录, 从一开始的 500KB (TiddlyWiki 本身的 320KB 再加上外挂), 累积到现在 710KB 大约一百多篇 文章 (tiddler), 渐渐觉得 TiddlyWiki 有变慢的迹象, 主要发生在两种情境 : 浏览器一开始载入 TiddlyWiki 的 HTML 档案 编辑或新增任何一篇 文章 (tiddler) . 上网搜寻关键字 TiddlyWiki Slow 之后, 发现两篇文章 : How big can my file get before it gets too slow/doesn't work? (tiddlywiki.org/wiki) Tips for speeding up performance on large TiddlyWikis (2007-07-05) 这两篇文章的重点大致相同, 由此可知确实有人遇到“TiddlyWiki 变慢”的问题, 而且也已经有公认的解决方法。 经过实验, 我建议采用下面两种方法 : 关闭“动画显示” 不要显示“最近更新” 关闭“动画显示”---- disabling animations “动画显示”的开关, 在 TiddlyWiki 右侧边栏的“偏好设定”, 而这一项也是我从一开始使用 TiddlyWiki 就采用的方法。 只是, 所有“偏好设定”都是存放在“浏览器的 Cookie”---- 包括“动画显示”在内 ----, 所以 换了一台电脑 或是 同一台电脑的不同浏览器, 或是 Cookie 遗失, 就得要再重新设定一次。 目前还在寻找“储存在档案里头”的“永远关闭动画显示” 的设定, 以便一劳永逸。 . 不要显示“最近更新” “最近更新”也在 TiddlyWiki 的右侧边栏, 它会显示依修订日期排序的文章列表。而叫它“最近更新”其实有点“名不符实”, 因为它显示的其实是依修订日期排序的“所有文章列表", 所以当文章数量变多时, 这个"最近更新"就会变成一条巨龙, 而且是"一条动态更新的巨龙"。不仅浏览器一开始载入 HTML 档案时, 需要花不少时间捞出资料来排序出这一条巨龙; 而且编辑或新增任何一篇文章 (tiddler) 时, 也同样要花时间来"动态更新这一条巨龙"。 所以, 前面提到那两篇文章的建议都是"不要显示最近更新"。而在作法上又可以细分成下面几种 : 直接把"最近更新"和"全部"从右侧边栏拿掉 改变右侧边栏的排序, 使得一般场合显示"预设文章"或其他内容 将右侧边栏的下半部"收合起来", 需要时再打开 (详情见 Tips for speeding … 的最末段) 比较 TiddlyWiki 载入内容的时间 为了比较每一种作法的改善幅度, 我依照 How big can my file get … ? 的说明, 打开后台选项, 让 TiddlyWiki 显示载入内容所花的时间 从右侧边栏的"偏好设定"开始, 点选"偏好设定"最下面的"进阶选项" 勾选 选项表格 下方的"显示未知选项" 勾选 chkDisplayInstrumentation ** 请留意这个设定是存放在"浏览器的 Cookie" , 所以改了设定之后, 不一定要存档, 只要关闭目前的 TiddlyWiki, 下次就会在右上角看到载入内容所花的时间, =&gt; 由测试结果可以得知 : "最近更新"、"全部"、"分类"和"预设文章"都是 动态文章, 都需要一些额外的处理时间, 只是"分类"和"预设文章"内容较少, 所需的时间也比较少。 这些动态文章只有显示的时候才会占用时间, 所以它们只要不是预设显示即可, 不一定要从右侧边栏删除 如果以缩短载入时间为目的, 最好的方法是在右侧边栏的下半部显示"静态文章"或"收合起来". 单位都是:ms Tiddler (1) 显示“最近更新” (2)显示“分类” (3)显示“预设文章” (4) 显示“静态说明” 原始 直接把“最近更新”和“全部”从右侧边栏拿掉。 保留“最近更新”和“全部”,但是调换页签的顺序, 让载入时显示“预设文章” 同左, 但是载入时显示另外增加的“静态说明” LoadShadows 4 6 5 5 LoadFromDiv 402 407 406 411 LoadPlugins 146 140 144 150 Notify 929 600 329 280 Restart 1223 778 508 440 Macro init 0 0 0 0 Total 2720 1947 1408 1302 (1) 原始的 SideBarTabs 如下 SideBarTabs : <&lt;tabs txtMainTab "最近更新" "依更新日期排序" TabTimeline "全部" "所有文章" TabAll "分类" "所有标籤" TabTags "更多" "其他" TabMore>&gt; (2) 直接把"最近更新"和"全部"从右侧边栏拿掉 =&gt; 让载入时显示"分类"。 ** 因为"分类"也是动态文章, 但内容较少, 所以稍省了一点时间。 SideBarTabs : <<tabs txtMainTab "分类" "所有标签" TabTags "更多" "其他" TabMore>> (3) 保留“最近更新”和“全部”, 但是调换页籤的顺序 =&gt; 让载入时显示“预设文章”。 ** “预设文章”("shadowed tiddler tab"或"Shadow Tiddlers") 同样还是动态文章, 但内容更少, 所以又再省了一点时间。 SideBarTabs : <<tabs txtMainTab "更多" "其他" TabMore "最近更新" "依更新日期排序" TabTimeline "全部" "所有文章" TabAll "分类" "所有标签" TabTags>> (4) 同(3), 但是载入时显示另外增加的“静态说明” ** "管理" 和前面的 "更多" 是同一个分页, 被移到最前面当作预设的分页, 叫它 "更多" 有点怪, 于是改名。另外再到 TabMore 增加一个“静态说明”页。 SideBarTabs : <<tabs txtMainTab "管理" "管理文章" TabMore "最近更新" "依更新日期排序" TabTimeline "全部" "所有文章" TabAll "分类" "所有标籤" TabTags>> TabMore : <<tabs txtMoreTab "说明" "参考资料" TW_HELP "未完成" "内容空白的文章" TabMoreMissing "未引用" "未被引用的文章" TabMoreOrphans "预设文章" "已预设内容的隐藏文章" TabMoreShadowed>> 加速TiddlyWiki 运行的其他选项 下面还有其他 加速 TiddlyWiki 运行 的选项, 但“不见得适用于每一个人”就是了 …… 调整使用的套件 (plugin) 开启“预设文章”- PluginManager, 可以看到每个 plugin 的大小和载入时间, 再依此调整使用的套件。在我自己这边, plugin 载入时间 都在 0 ~ 5ms, 所以下面提到的“使用外部 js 档的方式安装套件”, 看来就没有这么迫切的需求。 文件体积822K,变得特慢 2.移除非必要套件、尽可能使用外部 js 档的方式安装套件 于 MarkupPostBody 宣告欲载入的套件: <script type="text/javascript" src="/pathto/YourPlugins.js"></script> 调整存档方式 偏好设定的“储存备份”和“自动存档”这两项, 也会影响 TiddlyWiki 运作的效能, 但和“文件保全”比起来如何取舍, 就没有一定的答案了。 本文转sinojelly51CTO博客,原文链接:http://blog.51cto.com/sinojelly/201364,如需转载请自行联系原作者
很多人都喜欢用Google Reader(简称GR)来订阅自己关注的朋友的最新文章,GR功能很强大,能够很方便的分享到twitter、Facebook等社会化网络上,默认没有提供分享到新浪微博,但可以自定义,下面详细介绍一下把GR文章分享到新浪微博的方法。 1、进入GR的设置界面。 2、切换到发送到页面。 3、在下面创建自定义链接。 网址:http://v.t.sina.com.cn/share/share.php?title=${title}&url=${url} 图标网址:http://t.sina.com.cn/favicon.ico 欢迎大家Follow me: 新浪微博:http://t.sina.com.cn/sinojelly Buzz: http://www.google.com/profiles/sinojelly twitter: http://twitter.com/sinojelly 本文转sinojelly51CTO博客,原文链接:http://blog.51cto.com/sinojelly/276119,如需转载请自行联系原作者
借助WebLog Expert能够分析网站的流量记录,本篇文章对其进行展开详细的介绍。 WebLog Expert能够分析网站的流量记录,从原始的流量记录中分析出Activity statistics、Access statistics、Information about visitors、Referrers、Information about errors等基本而重要的信息,能够帮助我们更加方便快捷地了解和分析网站的使用状况。该工具可针对Apache、IIS服务器的日志进行分析,使用起来非常简便。 接下去,从WebLog Expert的安装到进行服务器日志分析,进而获得性能需求逐步揭开这一工具的面纱。 最新版本的WebLog Expert软件可从http://www.weblogexpert.com/下载获得,安装过程非常简单,这里不再赘述。 安装完成后,点击【开始】—【程序】—【WebLog Expert Lite】—【WebLog Expert Lite】打开WebLog Expert工具,进入WebLog Expert使用主界面,如图1所示。列表中显示的每行记录为一个分析对象,针对每条记录都可进行“编辑、删除和分析”操作。 图1 认识了WebLog Expert主界面后,我们来创建一次日志分析。在主界面上点击【New】按钮,将弹出General对话框(如图2),在该对话框中分别填写Profile、Domain和Index。其中,Profile表示在主界面和分析报告中显示的名字;Domain为网站的域名;Index为分析报告的首页文件名。 点击【下一步】按钮,将显示如图3所示对话框。在此对话框中输入等分析的日志文件名(可使用通配符),如:c:\logs\access.log或c:\logs\*.log。 、 图2 图3 点击【完成】,将在图1所示的主界面中增加一条新的记录。 在主界面中,选中新添加的名为“Weind Site”的记录,点击【Analyze】按钮启动分析功能。一段时间后,即可生成一份较完备的日志分析结果文件,如图4所示。 图4 日志分析结果文件中呈现出了很多实用的信息,如:概要统计、活动统计、访问统计、访问者统计等。这些信息可为性能测试用例与场景设计提供有力支撑。下面,以河北师范大学软件学院Apache服务器的日志文件分析结果为例,对分析结果中的各项信息进行解释。 我自己单位的Apache服务器的日志文件主要记载的是“Bugfree缺陷管理系统的访问情况”。图5给出了Bugfree系统在2008年12月11日至 2010 年12月30日期间的系统访问日志分析报告的概要统计信息(General Statistics)。 图5 General Statistics(概要统计):对系统当前的一些基础性能指标进行统计,提供出相应指标的一些平均和总计数值。这一信息有助于我们掌握系统在某段时间内的整体情况,如:PV(页面访问量)。从图1.14可知,在2008年12月11日至 2010 年12月30日期间,Bugfree系统共有5417用户进行访问(Visitors),点击量达到1670868次(Hits),页面访问量达到492092次(Page Views),总带宽使用8.85GB。 Activity Statistics(活动统计):General Statistics提供了整个系统在运行期间,某些指标的平均和总计数值,但对性能测试而言,这些平均和总计数值往往是不够的,我们还需要查看一些峰值数据,或者说更希望看到各指标在不同时间段内的值分布情况。Activity Statistics就能提供出每天甚至每小时内各项指标数据,如每日用户访问量、每日点击量、每小时用户访问量、每小时点击量等。根据这些数据生成的图表反应了相关指标的分布趋势和峰值。图6和图7显示了我工作单位Bugfree缺陷管理系统的Activity Statistics信息,从图表中很容易查看各指标的分布趋势和峰值,轻松分析出某天或某个时间段的峰值数。这些数据在用例和场景设计时十分有用。 图6 图7 Access Statistics(访问统计):Activity Statistics提供每天、每小时的各项指标数据,侧重于各指标在时间上的分布,而Access Statistics反应的是业务或页面等的访问次数。Access Statistics菜单下支持按系统中页面、文件、图片、目录及入口页面的统计分类。Access Statistics可帮助我们确定性能测试的主要业务点(性能测试不同于功能测试,不能针对于整个系统的所有功能都开展性能测试,耗费人力物力且没有实际意义),从而更加真实有效的模拟大量用户的操作。图8显示了软件学院Bugfree缺陷管理系统的Access Statistics信息(这里涉及图表过多,只是进行了部分展示)。从图表中可得出“每日页面访问趋势”及“最热门的访问页面”,这些信息对性能测试的用例及场景设计具有很强的参考价值。 图8 Visitors(用户统计):提供依据IP来分类统计的点击量、用户访问量及带宽等各指标值,如图9,它能够帮助我们更好的分析访问用户的类型及带宽等用户感受。 图9 以上介绍了使用WebLog Expert进行性能需求分析的常用图表。实际上,WebLog Expert中还有其他的很多图表,如Referrers(提交统计):可提供最热站点、最热URL等指标分布数据;Browsers(浏览器统计):可提供用户使用的各类浏览器和操作系统的分配比例,方便读者在性能测试中更真实的模拟用户使用情况;Errors(错误统计):可提供系统运行期间出现错误的统计,通过这些信息能够帮助读者定位系统中存在的问题,进而通过分析问题发生原因,在新版本系统中有效避免等。 总之,WebLog Expert工具简单易用,功能强大,能够帮助读者有效地分析系统日志,进而更好地开展性能需求分析工作。建议读者结合一个日志文件,使用该工具进行一次性能需求分析,从而更深刻地理解各图表含义。 注意: 除了WebLog Expert工具之外,市场上还有很多款不错的日志分析工具,可以帮助我们针对不同的日志文件进行分析统计,进而帮助我们方便的获取性能测试需求。这里汇总了一些较常用的软件共享给大家,有兴趣的读者可以进行研究分析。1)Analog:开源软件,免费;2)AWStats:开源软件,免费;3)Webalizer:开源软件,免费;4)Summary:商业软件,有30天试用版;5)WebTrends:商业软件。 到此有关 论“性能需求分析”系列专题 就搞一段落,希望大家多多交流。 本文转自hblxp32151CTO博客,原文链接:http://blog.51cto.com/starpoint/1320439,如需转载请自行联系原作者
XXX管理平台项目经理能力 前言 现在网络上比较热衷于数字化评选项目管 理人员的能力,最典型的代表如以下文章: IT项目经理必备的五种能力 http://cio.it168.com/e/2006-10-22/200610221947269.shtml IT管理人才必备的十大能力 http://space.itpub.net/3001/viewspace-611924 此外在也有PMI中对IT管理人员的能力有所要求和定义。 本人也根据自身的项目 经历和从业经验,分享一下自己对项目管理人 员所需能力的理解;当然不同软件能力成熟度的公司对 于项目经理能力要求也不尽相同,人不能脱离大环境而存在;以下能力按重要程度进行排序。 沟通能力 与销售人员、售前人员相比,技 术人员的最大差距在哪里?就是沟通能力。无论从拜访客户、需求调研、商务谈判、与公司的上下级沟通还是甲乙双方的人际 关系,感觉商务人员确实要比纯粹的技术人员高明很多;项目经理相当于半个商务人员,我也一致致力于此,但从和商务人员近一年的相处而言,确实要学习的太多了。 项目经理的沟通主要包括内部沟通和外部沟通。外部沟通是与甲方和相关方的沟通,包括甲方的领导,项目 经理,技术人员,以及相关接口系统的友商,沟通的目的在于确认双方需求、系统进展、相关协调等等。内部沟通主要是与公司内部的沟通,包括公司相关高层领 导,平级协助部门,团队成员,主要目的是为了创建一个良好的工作氛围,尽可能屏蔽与项目无关的损耗,使团队集中精力到项目过程中去。 针对不同的对象沟通的方式也是不同。外部沟通过程中甲乙双方的地位实际上是不平衡的,乙方处于弱势位 置,为了避免命令式的强制/被压制,服从/被服从的发生,最好是双方建立良好的朋友关系,这样甲方既可以及时了解项目的进展,也可以了解项目经理和项目所面临的困难,以期达到部分谅解; 外部沟通也包括一些营销活动,这取决与甲方的喜好和公司的财务制度,呵呵。关于这一点,销售人员更有发言权。 内部沟通中与公司高层领导的沟通主要是进行耐心说服工作,通过邮件电话均可,当然如果无法对领导实施 相应的压力比如资源,也可以借助甲方的力量(这是下下策);与部门评级之间的沟通,要尽量采用温和的手段,为了避免无效沟通最好知公司高层、其直接领导,然后 再进行沟通;与团队成员的沟通,首先是进行会议沟通,会议沟通主要发生在项目的关键点上,比如项目启动会、项目验收会,或者重大事项的时候,频繁的会议沟 通,我不认为有太大用途,尤其是人多的时候;其次是1对1的沟通,与下面的项目经理和团队成员进行面对面沟通,可以及时了解项目进展、团队成员的思想波动,有 针对的为其提出建议、解决方案,让团队成员感觉到项目经理的人文关怀,并传达公司的温暖;最后是避免不了的项目活动,聚餐、爬山、电影都是很好的活动方 式,这取决与项目经理的权限和公司的财务制度。 关于沟通的目的,如何进行沟通、要解决什么问题,大体可以按如下步骤来做: 是什么? 为什么? 怎么做? 这几点看起来很容易,实际上包含了你对问题的理解、总结、思考、应急能力;记住这三点,并应用在你今后的沟通过程中(比如会议、电话、邮件),相信对改善和提高你的沟通能力和沟通效 果有很大的帮助。 组织能力 建立核心团队: 这里的核心团队是指子项目的项目经理和关键技术人员,具体视不同的项目规模而定,人员的管理和沟通是有成本的,我个人认为3-5个人比较合适,太多的人员太多的细节 靠一个人有限的精力是无法进行跟踪和控制的;当然这里的核心团队成员是指那些技术和架构水平高超、有一定的项目管理能力、善于团队协助的人;核心团队成立 越早越好,有利于项目的稳定和提前进入角色。如前文中所述,不善于团队协助的人只能带来负面效应。 协作能力 协作能力主要表现在项目内部各团队之间的协作、与公司内部其他团队的协作,与项目相关的友商的协作能力上。 项目管理能力 软件工程 软件工程按照传统的理解即需求分析、系统设计、系统开发、系统测 试,这对项目经理而言是最起码的要求;就大部分国内项目而言,项目经理还是要样样都懂一点的,我不太赞同工作2、3年就自命不凡担当项目经理的人,技术、业 务、人际关系的把握的积累都是需要时间的;当然外企也有职业的项目经理,他们可以不专技术,而专注过程。 软件能力成熟度 软件过程能力(Software Process Capability):描述了在遵循一个软件过程后能够得到的预期结果的界限范围。该指标是对能力的一种衡量,用它可 以预测一个组织(企业)在承接下一个软件 项目时,所能期望得到的最可能的结果。IT企业有自己的软件能力成熟度,当然个人也有自己的软件能力成熟度,即体现在个人对过程的定义、监控、 跟踪和度量上。本人有幸在3家CMM5的公司工作过,不过仍称不上对CMM有多深的研究,一来过于繁琐,再则软件能力成熟度与所在的IT环境有密切的关系,过程的实施和度量需要 一系列的保障;事实上严格遵循CMM流程的企业并不多,基本上都是为了内部评估而评估的;不过基于过程的思想值得项目去参考和学习。 关于本项目的话,如果一定要说有什么软件能力成熟度的话,我认为是2级吧,项目管理的基本流程和系统文档已经有 了,做类似的项目是具备一定的复制性的。 架构能力 系统架构,这个与项目经理的角色和定位有一定 关系,项目经理需要从整体上把握系统的各个环节,硬件、操作系统、数据库、软件、软件框架、甚至测试,都需要有所涉猎,能做到一 精多专已经是不错的状况了,能做到全能的人应该是大师级的人物了,至少我不是,呵呵。 系统集成,这项能力与具体的项目有关,对于小项目来说只需要完成相应的业务功能,对性能的考虑、系统扩展型、系统部署、外围系统的接口要求并不 高,所以对系统集成考虑的较少;如果实施大中型项目的话,项目经理最好具备起码的思想和评估能力。 关于系统架构、系统集成能力的提高,需要本身知识储备的日积月累、阅读大量的相关资料、以及项目实施 过程中的学习,除此之外,别无办法。 学习能力 技术学习 项目经理需要的一个最基本的能力便是对他们的基本技术技能进行深度和广度的拓展。目前的技术知识更新 换代过于频繁,但技术本身的内涵确实恒久不变的。如Oracle从9i到11g,其Concept变更的并不多,其基于关系的数据库特性在短期内还是无法改变的;如java和.net之争,其核心仍是面向对象的;如各技术框架之选型,无非是实现展现层、业务逻辑层、控制层、数据持久 层的分离;适当的扩展自己的技术能力也是与时俱进的一种体现。 业务学习 相比技术而言,业务是更难学习的,尤其是财 务、ERP、金融 证券业务等,与IT背 景相距深远,但是又不能不学,作为项目经理需要与甲方业务方进行沟通,缺乏相关知识背景,会造成沟通上的鸿沟,甚至无法理解对方的意图。当然并不是说项目 经理一定要成为业务专家,事实上也是不太可能的。 文档能力 项目经理一定要会写,这是由项目经理的工作性质所决定的,从解决方案、系统架构、需求文档、验收文 档的编写,到设计文档、测试文档的规格要求,无不打上项目管理人员的烙印;撰写文档是组织自己思路进行深层思考的过程,如果文档无法表达明白的话,相信自 己的思考也一定不成熟;撰写文档也是沟通的需要,会议纪要、需求文档如果写的不清不楚的话,双方如果进行确认?想清楚才能写明白这是很简单的一个道理。 总结 项目经理的能力依据项 目的规模和公司的成熟度有不同的要求,不能一概而论;举例而言,在本系统中假设时间为100的话,各项过程所占的比例分别如下: 本文转自baoqiangwang51CTO博客,原文链接:http://blog.51cto.com/baoqiangwang/313500,如需转载请自行联系原作者
如何将 Symantec AntiVirus 企业版客户端从不接受管理更改为接受管理情形将 Symantec AntiVirus Corporate Edition (Symantec AV) 10.0 作为不接受管理的客户端进行了安装。您想要将它更改为接受管理的客户端。解释从父服务器将Grc.dat 文件复制到想要管理的客户端。 注意:若将客户端移入一个客户端组,请在下面的步骤中用 Grcgrp.dat 代替 Grc.dat 。 在父服务器上定位 Grc.dat 文件: 如果父服务器采用的是 Windows NT 操作系统,那么应从父服务器上的 VPHOME 共享文件夹复制 Grc.dat 文件。默认情况下,共享文件夹指向父服务器上的 <OS Drive>:\Program Files\NAV。 注意: 如果 Symantec AV 是从Norton AntiVirus Corporate Edition 7.x 升级的,那么默认文件夹是 <OS drive>:\Program Files\NAV\。 如果父服务器采用的是 NetWare 操作系统,则应从 SYS:NAV 文件夹下复制 Grc.dat 文件。 将 Grc.dat 文件复制到客户端: Windows 98/Me 客户端,应将 Grc.dat 文件复制到客户端上 Symantec AV 的安装文件夹下。Windows 95/98 客户端的默认文件夹为: C:\Program Files\Symantec_Client_Security\Symantec AntiVirus如果程序是从 Norton AntiVirus 企业版升级的,默认文件夹为: C:\Program Files\Norton AntiVirus Windows NT 客户端,请将Grc.dat 文件复制到下面的文件夹: <OS Drive>:\WINNT\Profiles\All Users\Application Data\Symantec\Norton AntiVirus Corporate Edition\7.5 对于 Windows 2000 或 XP 客户端,必须将 Grc.dat 文件复制到以下文件夹: <OS Drive>:\Documents and Settings\All Users\Application Data\Symantec\Norton AntiVirus Corporate Edition\7.5 注意: 在 Windows 2000 中,Application Data 文件夹是隐藏的。要显示隐藏和系统文件,请阅读文档:如果显示 Windows 中的隐藏文件和受保护的操作系统文件(英文)。 如上所示,Symantec AV 10.0 在一些操作系统上使用文件夹: \Norton AntiVirus and \Norton AntiVirus Corporate Edition\7.5 几分钟后,Symantec AV 客户端就会在此文件夹下找到 Grc.dat 文件。Symantec AV 会在对注册表进行适当的更改后删除该文件。下次客户端向父服务器登记时,就会显示在 SSC 中。通过停止、然后启动客户端上的 Symantec AV 客户端服务或重新启动计算机,强制执行登记。 ------------------------------------------------------- 全文完! 本文转自redking51CTO博客,原文链接:http://blog.51cto.com/redking/15734,如需转载请自行联系原作者
本季介绍了面向对象与面向过程的区别,重点阐述了类与对象的关系及JAVA中如何定义类和使用对象。之后又详细讲解了对象的引用传递和垃圾的产生。 面向对象是JAVA中最核心,最重要的部分,在此概念非常多,需要反复理解。 本季目标 此次目标是整个Java SE面向对象基础部分的目标哈,一共划分七个季讲解哈,同时会辅以大量的练习来巩固所学知识。OK,废话不多说,go on~~~ 面向对象与面向过程的比较 面向对象的前身是叫面向过程。 面向对象的分析过程就可以称为类的设计。 面向对象的三大特征 封装可以有效的保护程序。在所有基础上扩展类的功能就是继承哈~~~ 类与对象 类与对象的区别和联系: 类是一个抽象的,是一个共性的东西 对象是类的具体的应用,是一个个性的东西 在面向对象中重点是类的设计。 类的定义格式 按此格式定义一个Person(人类) 假设Person类中只包含姓名和年龄; 现在我们成功定义了一个Person类,它有两个属性,分别是name和age,现在这个类有了,我们就可以使用它,重点是类的设计。要使用这个类的唯一方法就只有产生对象。我们再为其加入一个方法,例如说话方法哈~怎么加入这个说话方法呢?我们看下面 对象的产生 在main方法中的重点就是产生对象,对象的产生格式是: 类名称 对象名称 = null ; ==> 声明对象 对象名称 = new 类名称() ==> 实例化对象 · new就表示要开辟新的内存空间。 注意:void say()方法,在这里讲一下哈,以前我们学习的方法主要是在主方法中直接调用的哈,所以我们在方法名称前面加入了一个public static,现在我们用对象调用方法的话,可以暂时不加哈,我们以后会讲清什么时候该加public static什么时候不该加public staic哈~ 现在写完后我们来验证一下效果哈~ 我们发现姓名:王乾和年龄:26都出来了哈,这就是最基本的类和对象的程序,我们发现并不是很复杂哈,只要按规则写就可以出来哈,我们继续往下学哈~ 这个程序我们写完也验证了哈,那其中到底发生了什么呢? 上面的图很重要哈,我们最好可以背下来哈,以及重点理解会下面的程序详解过程哈~~ 程序详解: 1、定义好一个类 2、为定义好的类实例化对象 · 声明对象:在栈内存中开辟空间 · 实例化对象(为一个对象开辟空间),使用关键字new完成。只要有new关键字就表示在堆内存中开辟空间,在堆内存中保存各个对象的属性。而方法是保存在全局代码区里面滴。 3、通过对象.属性为类中的属性赋值,通过对象.方法()调用类中的方法。 我们明白了上面的过程,那我们能否通过以上的格式产生第二个对象呢? 我们看到可以产生第二个对象哈,如果要产生三个以上的对象也是按照这样的格式依次类推哈~~~ 面向对象这个部分必须着重观察内存的分配。 类是一个引用的传递的数据类型。 我们发现,如果我们没有对对象开辟堆内存空间的话,程序执行会报NullPointerException错哈~,如果我们发现出现这个错误,我们排错时就检查对象有没被实例化。 NullPointerException : 空指向异常,只要是没有堆内存引用的对象,直接调用对象访问属性或方法的时候都会出现空指向异常。此异常会伴随你的开发人生。 下面如果我们再加一条代码,p2=p1;将p1的值赋给p2,这样p1和p2就都指向了堆内存中的同一个空间。这样我们无论对p1还是p2进行修改,都将对其指向的同一个堆内存空间的属性进行修改。 内存的分配情况: 现在调用的p1.say();和p2.say();应该输出都是一样的内容,就是最后p2.name和p2.age所赋的值。我们验证一下效果哈。 这就是一个典型的引用传递例子,下面我们基本上讲到的都是引用传递哈~ 观察以下的程序,分析其内存的分配过程: //声明对象同时实例化对象 Person p1=new Person(); Person p2=new Person(); p1和p2分别在堆内存中开辟空间 //将p1的值赋给p2,这样p1和p2就都指向了堆内存中的同一个空间 p2=p1; 当p1的值要赋给p2时,p2先断开其刚才在堆内存中开辟空间的连接,然后再p2与p1所开辟的空间建立连接。 下面的内存储器分配情况就和ooDemo03一样了哈,我们看下效果 我们发现原来p2开辟的那块空间没有用处了,没用的空间我们就称其为垃圾,垃圾会被垃圾收集(GC)自动回收。—— 垃圾的产生过程。 总结: 1、类与对象的关系 · 类是对象的模板,对象是类的一个实例 2、对象的创建 ·声明对象:在栈内存中声明;类名称 对象名称 = null ; ·实例化对象:使用new在堆内存中开辟空间,保存属性;对象名称 = new 类名称() ; 3、对象的引用传递 4、垃圾的产生。 本季内容是以后内容很基础的部分哈,我们一定要理解类与对象的关系,以及一个最重要的一个错误:NullPointerException(空指向异常). 本文转自redking51CTO博客,原文链接:http://blog.51cto.com/redking/119347,如需转载请自行联系原作者
在LINUX下面架设DNS服务器,不知道DNS解析原理,根本会了和不会没区别, 网络中为了区别各个主机,必须为每台主机分配一个惟一的地址,这个地址即称为“IP地址”。但这些数字难以记忆,所以就采用“域名”的方式来取代这些数字了。 当某台主机要与其他主机通信时,就可以利用主机名称向DNS服务器查询该主机的IP地址,所以我们的网卡要上网至少要3个信息,IP地址,网关,DNS服务器地址。 DNS的组织结构 这个就是DNS的组织结构,最上面是根域名 dot,全球13台根域服务器,没有一台在中国,因为中国网络发展,起步迟。而且所有的dot DNS服务器都是bind软件架设的,我们今天要学习的也是bind软件。全球70%的大型DNS服务器都是基于bind软件。 常见的顶级域服务器 我国的顶级域也就只有cn DNS解析过程 我给大家解释下,比如解析[url]www.redhat.com[/url],第一步,查询本地host文件和缓存有没有这个记录,有就直接解析,没有就访问DNS服务器,如果DNS服务器上没[url]www.redhat.com[/url]或者redhat.com不在你访问的DNS服务器管理区域内,那么DNS服务器就会向dot根域名服务器发递归查询,如果找到了记录了,DNS就会返回给client,并且把记录保存在自己缓存里,下次有client请求,他就会调用自己的缓存,直到这条记录的生存期结束,就会丢弃这条记录。 根域名服务器就13台域名服务器,他负责管理顶级域。顶级域负责管理二级域,我们现在申请的一般是2级域名-3级域名。比如michael.com,michael.com.cn哈~michael.com是2级域名,michael.com.cn是3级域名,michael.com.cn.这个就是FQDN。 本周我们要学习的内容 主配置文件 设置根区域 设置主区域 设置反向解析区域 根服务器信息文件named.ca 区域文件 反向解析区域文件 实现负载均衡功能 实现直接解析域名 实现泛域名的解析 主要名称服务器的测试 配置辅助域名服务器 配置缓存域名服务器 我们申请的是域名,然后你去管理你的域名,自己添加主机记录哈~ 其实michael.cn是域名,前面的主机记录随便你怎么写,abc.michael.cn也行,jfajldjfklajdfkljaklf.michael.cn也行,michael.com是域名,www是主机。 比如[url]www.redhat.com[/url],[url]www.redhat.com.[/url] 最后点是根域名,然后com是顶级域名,redhat是二级域名,www是主机记录,如果你要说[url]www.redhat.com[/url]是域名也可以,那么主机就改成是[url]www.www.redhat.com[/url].了,在选择域名时必须符合RCF 1123中的规定:域名由所有大写字母(A~Z)、小写字母(a~z)、数字(0~9)和连字符(-)组成。由于很多域名商,所以现在想申请到好的2及域名是不可能了,域名大小写不敏感。 每台主机都有一个host文件,负责IP地址的域名快速解析的文件,文件以ASCII格式保存在“/etc”目录下,文件名为“hosts”,hosts文件包含了IP地址和主机名之间的映射,还包括主机名的别名。 hosts文件的格式如下: IP地址 主机名/域名 主机别名 windows下也有hosts文件,C:\WINDOWS\system32\drivers\etc 可以使用记事本打开 如果host里有记录就会优先使用,这个文件也是黑客,和病毒软件攻击你的一个入口,如果某个病毒软件在这个文件添加一个记录202.23.23.1 [url]www.163.com[/url],然而前面这个IP地址是带有病毒的而已网站,或者是钓鱼攻击,你可能就会出问题,所以这个文件一般修改成只读,还有些第三方软件,为了防止一些木马之类的病毒,会把一些有问题的网站在自理定义,解析成127.0.0.1,这样你就不会访问到这些网站,360就会这么干哈~ linux也有这个文件 /etc/hosts 好了,下面介绍下bind软件,Linux下架设DNS服务器通常是使用Bind程序来实现的。 Bind是Berkeley Internet Name Domain Service的简写,它是一款实现DNS服务器的开放源码软件。Bind原本是美国DARPA资助伯克里大学(Berkeley)开设的一个研究生课题,后来经过多年的变化发展,已经成为世界上使用最为广泛的DNS服务器软件,目前Internet上绝大多数的DNS服务器有都是用Bind来架设的。 DNS服务介绍 后台进程:named 脚本:/etc/rc.d/init.d/named 使用端口:53(tcp,udp) 所需RPM包:bind-9.3.3-10.el5 相关RPM包:bind-chroot caching-nameserver 配置文件:/var/named/chroot/etc/named.conf 相关路径:/var/named/ 1990年以后,bind-chroot增加了bind服务器的安全性,早期Linux服务都是以root权限启动和运行的,随着技术的发展,各种服务变得越来越复杂,导致BUG和漏洞越来越多。黑客利用服务的漏洞入侵系统,能获得root级别的权限,从而控制整个系统。 为了减缓这种攻击所带来的负面影响,现在服务器软件通常设计为以root权限启动,然后服务器进程自行放弃root,再以某个低权限的系统账号来运行进程。这种方式的好处在于该服务被攻击者利用漏洞入侵时,由于进程权限很低,攻击者得到的访问权限又是基于这个较低权限。 bind的主配置文件/etc/named.conf ,我们先安装bind服务器 [root@rhel5 ~]# rpm -ivh /mnt/cdrom/Server/bind-9.3.3-10.el5.i386.rpm warning: /mnt/cdrom/Server/bind-9.3.3-10.el5.i386.rpm: Header V3 DSA signature: NOKEY, key ID 37017186 Preparing... ########################################### [100%] 1:bind ########################################### [100%] [root@rhel5 ~]# rpm -ivh /mnt/cdrom/Server/bind-libbind-devel-9.3.3-10.el5.i386.rpm warning: /mnt/cdrom/Server/bind-libbind-devel-9.3.3-10.el5.i386.rpm: Header V3 DSA signature: NOKEY, key ID 37017186 Preparing... ########################################### [100%] 1:bind-libbind-devel ########################################### [100%] [root@rhel5 ~]# rpm -ivh /mnt/cdrom/Server/bind-sdb-9.3.3-10.el5.i386.rpm warning: /mnt/cdrom/Server/bind-sdb-9.3.3-10.el5.i386.rpm: Header V3 DSA signature: NOKEY, key ID 37017186 Preparing... ########################################### [100%] 1:bind-sdb ########################################### [100%] [root@rhel5 ~]# rpm -ivh /mnt/cdrom/Server/bind-devel-9.3.3-10.el5.i386.rpm warning: /mnt/cdrom/Server/bind-devel-9.3.3-10.el5.i386.rpm: Header V3 DSA signature: NOKEY, key ID 37017186 Preparing... ########################################### [100%] 1:bind-devel ########################################### [100%] [root@rhel5 ~]# rpm -ivh /mnt/cdrom/Server/caching-nameserver-9.3.3-10.el5.i386.rpm warning: /mnt/cdrom/Server/caching-nameserver-9.3.3-10.el5.i386.rpm: Header V3 DSA signature: NOKEY, key ID 37017186 Preparing... ########################################### [100%] 1:caching-nameserver ########################################### [100%] [root@rhel5 ~]# rpm -ivh /mnt/cdrom/Server/bind-chroot-9.3.3-10.el5.i386.rpm warning: /mnt/cdrom/Server/bind-chroot-9.3.3-10.el5.i386.rpm: Header V3 DSA signature: NOKEY, key ID 37017186 Preparing... ########################################### [100%] 1:bind-chroot ########################################### [100%] [root@rhel5 ~]# 注意:bind-chroot软件包最好最后一个安装,否则会报错哈~~~ bind的配置文件默认是没有的,需要自己手写,但是很多,容易写错,所以我们安装模板文件,然后来修改。由于安装了chroot环境,所以我们的/etc/named.conf 应该在/var/named/chroot/etc/ 目录。 没有named.conf,所以我们要把named.caching-name.conf文件copy一份成named.conf哈~ cp /var/named/chroot/etc/named.caching-nameserver.conf /var/named/chroot/etc/named.conf 编辑named.conf这个文件,把文件里面多余的东西删除了,只剩下如图中的内容,然后我们来写 先检查你主机的名字,使用hostname 记住,linux的主机名要是FQDN的样式,把你们自己的主机名字改改,不要最后的那个,这个很重要的。 刚才讲了FQDN最后有根域的,把那个跟域去掉,就是你的主机名,改成那个样子。 linux修改主机名字修改三个地方,不知道大家还记得不? 第一步:hostname 主机名 第二步:vim /etc/hosts 第三步:vim /etc/sysconfig/network 修改完了把终端关闭了,然后重新打开就可以了 修改完了,我们继续 下面我以michael.com这个二级域名来建立一个域名服务器 全局配置(options ) options 语句在每个配置文件中只有一个。如果出现多个options, 则第一个options 的配置有效,并会产生一个警告信息。 listen-on port 53 { 127.0.0.1; }; 监听端口,修改成自己的IP地址,如果有多个IP,就写多个,每行要以;结束。 directory "/var/named"; zone文件的存放目录,这里的/var/named 是相对目录,在chroot环境下/var/named目录下。 allow-query { localhost; }; 允许查询的client,我们修改成本地网段192.168.1.0/24 下面我们开始写zone文件 区域配置(zone ) zone 语句作用是定义DNS 区域,在此语句中可定义DNS 区域选项 zone区域设置,第一步,设置根区域 当DNS服务器处理递归查询时,如果本地区域文件不能进行查询的解析,就会转到根DNS服务器查询,所以在主配置文件named.conf文件中还要定义根区域。 zone "." { type hint; file "named.ca"; }; type:设置域的类型 file:设置根服务列表文件名 “.” 意思的根区域 IN 是internet记录 type是类型 根的类型是hint file是根区域文件 下面我们去看看根区域文件,根的类型 这些就是根服务器,你数数,全球13台。 继续,指定正向解析的配置文件 记住,bind对配置文件要求很严格,就算是有些地方多了个空格,服务器都可能启动不了哈~ 反向解析配置文件 一个简单的named.conf配置文件 保存,然后我们去修改区别文件,添加记录 cp /var/named/chroot/var/named/localhost.zone /var/named/chroot/var/named/michael.com.zone michael.com.zone 是你刚才在named.conf里面定义的名字,记住,要和那个一样 反向区域的zone名字,必须是这样的命令方式,把IP地址反过来表达 vim /var/named/michael.com.zone TTL是生存期,单位是秒 $TTL是全局定义的 第二行 SOA记录,@取代在/etc/named.conf中指定的域名。 SOA段中的数字,分别为:序列号、刷新、重试、过期、生存期 序列号:序列号用于DNS数据库文件的版本控制。每当数据被改变,这个序列号就应该被增加。 刷新:从服务器向主服务器查询最新数据的间隔周期。每一次检查时从服务器的数据是否需要更改,则根据序列号来判别。 重试:一旦从服务器尝试连接主服务器失败,下一次查询主服务器的延迟时间。 过期:如果从服务器无法连通主服务器,则在经过此时间后,宣告其数据过期。 生存期:服务器回答 ‘无此域名’ 的间隔时间。 数字的默认单位为秒。否则:W= 周、D= 日、H= 小时、M= 分钟。 下面我们来写自己的ZONE文件 IN 是internet记录 SOA 是SOA 初始化记录,我们说的是初始授权记录,这个翻译不过,理解很多反正知道是那个意思就行了 mail.michael.com. 是DNS服务器的名称 root.unix.com. 是管理员的邮箱地址 版本号改成日期后面加两个00,其他都默认,下面开始添加主机记录 第一个NS记录 NS(name server):设置域名服务器的域名 然后添加一个MX记录 MX (Mail eXchanger ): 设置邮件交换器资源记录 简单的正向配置文件就到这里,下面接着讲反向解析的zone文件 把正向解析zone文件拷贝一份,名字是你在named.conf中定义的反向解析的名字 cp /var/named/chroot/var/named/michael.com.zone /var/named/chroot/var/named/1.168.192.in-addr.arpa.zone 然后我们来修改反向解析 vim /var/named/1.168.192.in-addr.arpa.zone SOA记录可以不修改,NS记录和MX记录也可以不修改 只需要把A记录修改成PTR记录就可以了,PTR是反向解析的意思,把IP地址解析成域名 然后保存退出 配置文件就写完了,下面我们来使用配置文件检测工具来检测我们的配置文件语法是否正确 named-checkconf /var/named/chroot/etc/named.conf 这个命令是检查named.conf主配置文件的,如果没有提示,就证明这个文件没有问题 检测区域文件的语法 语法为named-checkzone 域名 配置文件 两个配置文件都要检查 named-checkzone michael.com /var/named/chroot/var/named/michael.com.zone named-checkzone michael.com /var/named/chroot/var/named/1.168.192.in-addr.arpa.zone 下一步就可以启动DNS服务了 启动失败,我们来排错,把日志文件检测起来 tail -f /var/log/messages chmod 644 /var/named/chroot/etc/named.conf 把named.conf配置文件的权限改成644就可以了,出现这些问题,大家就要学会分析日志。 我们来配置client,然后来测试我们DNS服务器是否架设成功 vim /etc/resolv.conf 修改成自己的IP地址,然后保存 我们现在来测试我们的DNS dig -t soa michael.com dig -t mx michael.com 这是dig 工具,查询 michael.com域中的SOA记录和MX记录 dig [url]www.michael.com[/url] 这是查询[url]www.michael.com[/url] dig mail.michael.com 这是查询mail.michael.com dig -x 是反向查询 dig -x 192.168.1.8 当然,还有简单的命令来查询dns解析,比如nslookup 和host 都可以 查不到哈~看下日志 chmod 644 /var/named/chroot/var/named/michael.com.zone chmod 644 /var/named/chroot/var/named/1.168.192.in-addr.arpa.zone 现在正常了我们测试下 nslookup 也可以,和win下的用法一样 ##################Michael分割线##################### 下面我们使用DNS来实现简单的负载均衡 这个技术在很早的时候被yahoo和163等网站使用实现过负载均衡,不过现在已经很少有企业这样做负载均衡了,因为这样负载均衡是随即的,他没有使用算法,不科学,但是我们也了解下吧,对于小企业还是可以考虑这样做的, 呵呵,真正的负载均衡听麻烦,不是三言两语说的清楚的,而且还要fence device的支持。 回到正体,DNS负载均衡的原理给大家说说 DNS负载均衡的优点是经济简单易行,它在DNS服务器中为同一个域名配置多个IP地址(即为一个主机名设置多条A资源记录),在应答DNS查询时,DNS服务器对每个查询将以DNS文件中主机记录的IP地址按顺序返回不同的解析结果,将客户端的访问引导到不同的计算机上去,使得不同的客户端访问不同的服务器,从而达到负载均衡的目的。 我们下面给www主机做负载均衡 那个0是这个记录的生存期 重新启动服务器 我们来测试下,我们用ping命令,测试ping [url]www.michael.com[/url]是不是每次ping到的IP不一样 ping了三次,每次ping到的主机都不一样,这样就简单的实现了负载均衡,现在国内负载均衡一般使用的lvs+heartbeat+HA,红帽有集群的专门解决方案GFS+conga+XEN LVS是集群技术,章文嵩教授开发的 heartbeat 是心跳线 HA 是高可用性,解决方案 这个就涉及到fence device ,电源交换机,光纤存储交换机,FASTER ethernet交换机 心跳线是BS和备份BS之间通信,如果BS宕机了,备份BS马上起来取代BS的任务,BS是负载均衡服务器 提提,有兴趣的自己下去研究吧 下一个功能,直接解析域名 我们在IE输入baidu.com 也能访问到baidu,这个就是使用了直接解析域名 现在我们没有直接解析域名,其实直接解析域名除了用在网站,还用在邮件服务器,这样就免去了编写出站表的麻烦事情,直接通过DNS的直接解析域来处理。 这个就是直接解析域名的写法,注意后面有个点 重新启动服务器,然后我们来测试 看见没有,把MX记录也解析出来了 实现连续解析域名 在一个企业中,可能有上百台计算机,如果要为每一个计算机分配一个域名,如果一条一条的添加到域文件中,则相当耗时。 $GENERATE 是函数 1-200 是要循环的变量 host$是主机名 192.168.1.$是对应的IP地址 反向解析我们也写上吧 重启下服务哈~ 现在1-200的主机我们都有解析了 这就是效果了 说说实现泛域名的解析 你们试过adfkjakldfjakldjf kl.baidu.com ,也能进入baidu的网站么?就是主机位置随便输入什么,都可以正确访问,我意思是主机名随便输入,以前baidu用来的,现在baidu没用泛域名了,用了直接域。 泛域名很简单,就是用*匹配所有,但是注意了,这个解析要放在最后,应为ZONE文件是从上到下读取的,当上面的都不匹配的时候才会读取泛域名解析。 保存退出,重启named服务哈~ 这样也可以解析,厉害吧 下面我们来测试辅助域名服务器 这个需要两个服务器,用辅助域名服务器给主域名服务器备份,当然也可以指一个NS记录到辅助域名服务器,这样为主域名服务器减轻负载 在主DNS的zone区域加allow-transfer 语句,指名那个client可以来复制我的zone文件,这个参数也可以放在options字段,放options全局有效。 把主DNS的刷新时间改小点 #######################Michael分割线########################## 未完待续哈~~~~~~~~~~~~~~~~ #######################Michael分割线########################## 本文转自redking51CTO博客,原文链接:http://blog.51cto.com/redking/146708,如需转载请自行联系原作者
–设置可滚动ResultSet –滚动ResultSet –更新ResultSet –RowSet ####################Michael分割线####################### • 设置可滚动ResultSet –为了获得可滚动ResultSet,我们必须用如下的方式来创建Statement或者PreparedSatement • 滚动ResultSet –rs.previous() –rs.relatice(n) –rs.absolute(n) –rs.getRow() –rs.first() –rs.last() –rs.beforeFirst() –rs.afterLast() –rs.isFirst() –rs.isLast() –rs.isBeforeFirst() –rs.isAfterLast() ConnectionUtil.java package com.michael.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.util.Properties; public class ConnectionUtil { //第一种方法 public Connection getConnection(){ Connection conn = null; try { //Class.forName加载驱动 Class.forName("com.mysql.jdbc.Driver"); //DriverManager获得连接 conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_db","root","mysqladmin"); return conn; } catch (Exception e) { e.printStackTrace(); } return null; } //第二种方法 public Connection getConnection(String driver,String url,String user,String password){ Connection conn = null; try { //Class.forName加载驱动 Class.forName(driver); //DriverManager获得连接 conn = DriverManager.getConnection(url,user,password); return conn; } catch (Exception e) { e.printStackTrace(); } return null; } //第三种方法 public Connection openConnection(){ String driver = ""; String url = ""; String user = ""; String password = ""; Properties prop = new Properties(); Connection conn = null; try { //加载属性文件 prop.load(this.getClass().getClassLoader().getResourceAsStream("DBConfig.properties")); driver = prop.getProperty("driver"); url = prop.getProperty("url"); user = prop.getProperty("user"); password = prop.getProperty("password"); //Class.forName加载驱动 Class.forName(driver); //DriverManager获得连接 conn = DriverManager.getConnection(url,user,password); return conn; } catch (Exception e) { e.printStackTrace(); } return null; } } TestResultSet.java package com.michael.jdbc; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class TestResultSet { public static void test(){ Connection conn = new ConnectionUtil().openConnection(); try { Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); //执行查询获得结果集 ResultSet rs = stmt.executeQuery("select * from UserTbl"); //定义行号 rs.next(); //相对定位 rs.relative(3); //绝对定位 rs.absolute(2); //移动游标到第一行 boolean b = rs.first(); boolean b2 = rs.last(); int rowNumber = rs.getRow(); //输出行号,即游标位置 System.out.println(rowNumber); System.out.println(b); System.out.println(b2); } catch (SQLException e) { e.printStackTrace(); } } } Main.java package com.michael.main; import com.michael.jdbc.TestResultSet; public class Main { /** * @param args */ public static void main(String[] args) { TestResultSet.test(); } } • 更新ResultSet –更新一行 更新第四条记录 TestResultSet.java package com.michael.jdbc; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class TestResultSet { public static void test(){ Connection conn = new ConnectionUtil().openConnection(); try { Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); //执行查询获得结果集 ResultSet rs = stmt.executeQuery("select * from UserTbl"); //绝对定位到第四条记录 rs.absolute(4); rs.updateString(2, "alibaba"); rs.updateString(3, "alimama"); //更新一行 rs.updateRow(); /* //定义行号 rs.next(); //相对定位 rs.relative(3); //绝对定位 rs.absolute(2); //移动游标到第一行 boolean b = rs.first(); boolean b2 = rs.last(); int rowNumber = rs.getRow(); //输出行号,即游标位置 System.out.println(rowNumber); System.out.println(b); System.out.println(b2); */ } catch (SQLException e) { e.printStackTrace(); } } } Main.java package com.michael.main; import com.michael.jdbc.TestResultSet; public class Main { /** * @param args */ public static void main(String[] args) { TestResultSet.test(); } } –插入一行 TestResultSet.java package com.michael.jdbc; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class TestResultSet { public static void test(){ Connection conn = new ConnectionUtil().openConnection(); try { Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); //执行查询获得结果集 ResultSet rs = stmt.executeQuery("select * from UserTbl"); //插入一行 rs.moveToInsertRow(); rs.updateString(2, "Jake"); rs.updateString(3, "123456"); rs.updateInt(4, 26); rs.insertRow(); /* 更新一行 //绝对定位到第四条记录 rs.absolute(4); rs.updateString(2, "alibaba"); rs.updateString(3, "alimama"); //更新一行 rs.updateRow(); */ /* //定义行号 rs.next(); //相对定位 rs.relative(3); //绝对定位 rs.absolute(2); //移动游标到第一行 boolean b = rs.first(); boolean b2 = rs.last(); int rowNumber = rs.getRow(); //输出行号,即游标位置 System.out.println(rowNumber); System.out.println(b); System.out.println(b2); */ } catch (SQLException e) { e.printStackTrace(); } } } • RowSet –可更新的ResultSet是强大的,但是在操作期间必须保持数据处于连接状态 –RowSet接口继承了ResultSet,提供了如下的实现类: • CachedRowSet: 允许断开连接操作 • WebRowSet: 能保存XML文件 • FilteredRowSet/JoinRowSet: 在rowset上SELECT/JOIN操作 • JdbcRowSet: 可以将一行封装为一个Java Bean ####################Michael分割线####################### 附件:http://down.51cto.com/data/2352859 本文转自redking51CTO博客,原文链接:http://blog.51cto.com/redking/163778,如需转载请自行联系原作者
测试框架 ? 1 2 3 4 5 mirrors.redking.com 192.168.188.10 master.redking.com 192.168.188.20 agent.redking.com 192.168.188.30 Puppet 要求所有机器有完整的域名(FQDN),如果没有 DNS 服务器提供域名的话,可以在两台机器上设置主机名(注意要先设置主机名再安装 Puppet,因为安装 Puppet 时会把主机名写入证书,客户端和服务端通信需要这个证书),因为我配置了DNS,所以就不用改hosts了,如果没有就需要改hosts文件指定。 1.关闭selinux,iptables,并设置ntp 采用CentOS-6.6-x86_64.iso进行minimal最小化安装 关闭selinux ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 [root@master ~]# cat /etc/selinux/config # This file controls the state of SELinux on the system. # SELINUX= can take one of these three values: # enforcing - SELinux security policy is enforced. # permissive - SELinux prints warnings instead of enforcing. # disabled - No SELinux policy is loaded. SELINUX=enforcing # SELINUXTYPE= can take one of these two values: # targeted - Targeted processes are protected, # mls - Multi Level Security protection. SELINUXTYPE=targeted [root@master ~]# sed -i '/SELINUX/ s/enforcing/disabled/g' /etc/selinux/config [root@master ~]# cat /etc/selinux/config # This file controls the state of SELinux on the system. # SELINUX= can take one of these three values: # enforcing - SELinux security policy is enforced. # permissive - SELinux prints warnings instead of enforcing. # disabled - No SELinux policy is loaded. SELINUX=disabled # SELINUXTYPE= can take one of these two values: # targeted - Targeted processes are protected, # mls - Multi Level Security protection. SELINUXTYPE=targeted [root@master ~]# setenforce 0 停止iptables ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 [root@node1 ~]# chkconfig --list |grep tables ip6tables 0:off 1:off 2:on 3:on 4:on 5:on 6:off iptables 0:off 1:off 2:on 3:on 4:on 5:on 6:off [root@node1 ~]# chkconfig ip6tables off [root@node1 ~]# chkconfig iptables off [root@node1 ~]# service ip6tables stop ip6tables: Setting chains to policy ACCEPT: filter [ OK ] ip6tables: Flushing firewall rules: [ OK ] ip6tables: Unloading modules: [ OK ] [root@node1 ~]# service iptables stop iptables: Setting chains to policy ACCEPT: filter [ OK ] iptables: Flushing firewall rules: [ OK ] iptables: Unloading modules: [ OK ] [root@node1 ~]# 设置ntp ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [root@master ~]# ntpdate pool.ntp.org [root@master ~]# chkconfig --list|grep ntp ntpd 0:off 1:off 2:off 3:off 4:off 5:off 6:off ntpdate 0:off 1:off 2:off 3:off 4:off 5:off 6:off [root@master ~]# chkconfig ntpd on [root@master ~]# service ntpd start Starting ntpd: [ OK ] [root@master ~]# 创建软件仓库 1.在mirrors.redking.com软件仓库服务器上安装EPEL源及yum-downloadonly和createrepo软件包 ? 1 2 3 4 5 6 7 8 9 10 11 [root@mirrors ~]# rpm -ivh http://mirrors.sohu.com/fedora-epel/6Server/x86_64/epel-release-6-8.noarch.rpm Retrieving http://mirrors.sohu.com/fedora-epel/6Server/x86_64/epel-release-6-8.noarch.rpm warning: /var/tmp/rpm-tmp.2hQx2e: Header V3 RSA/SHA256 Signature, key ID 0608b895: NOKEY Preparing... ########################################### [100%] 1:epel-release ########################################### [100%] [root@mirrors ~]# yum -y install yum-downloadonly createrepo 2.创建软件仓库地址,选择/data/mirrors目录作为软件仓库目录 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 [root@mirrors ~]# mkdir -pv /data/mirrors/centos/6/{os,updates}/x86_64/RPMS mkdir: created directory `/data' mkdir: created directory `/data/mirrors' mkdir: created directory `/data/mirrors/centos' mkdir: created directory `/data/mirrors/centos/6' mkdir: created directory `/data/mirrors/centos/6/os' mkdir: created directory `/data/mirrors/centos/6/os/x86_64' mkdir: created directory `/data/mirrors/centos/6/os/x86_64/RPMS' mkdir: created directory `/data/mirrors/centos/6/updates' mkdir: created directory `/data/mirrors/centos/6/updates/x86_64' mkdir: created directory `/data/mirrors/centos/6/updates/x86_64/RPMS' 3.将Nginx、Puppet软件包存放到软件仓库,采用downloadonly的方式进行更新 puppet不在CentOS的基本源中,需要加入 PuppetLabs 提供的官方源 ? 1 2 3 [root@mirrors ~]# rpm -ivh http://yum.puppetlabs.com/el/6/products/x86_64/puppetlabs-release-6-7.noarch.rpm [root@mirrors ~]# yum install nginx puppet-server puppet -y --downloadonly --downloaddir=/data/mirrors/centos/6/updates/x86_64/RPMS/ 4.采用createrepo创建仓库文件,如果软件包比较多时可以通过--update参数进行更新 ? 1 2 3 [root@mirrors ~]# createrepo /data/mirrors/centos/6/os/x86_64/ [root@mirrors ~]# createrepo /data/mirrors/centos/6/updates/x86_64/ 5.在软件仓库服务器前端安装配置Nginx Web来处理安装包请求 ? 1 2 3 4 5 [root@mirrors ~]yum install -y nginx [root@mirrors ~]# service nginx start [root@mirrors ~]# chkconfig nginx on 6.为软件仓库配置mirrors.redking.com虚拟机 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 [root@mirrors ~]# vim /etc/nginx/conf.d/mirrors.redking.com.conf server { listen 80; server_name mirrors.redking.com; root /data/mirrors; index index.html; } [root@mirrors ~]# service nginx restart 通过上面6步就成功搭建本地软件仓库,在客户端只需要配置repo文件就可以安装此软件仓库中的软件包。 配置YUM本地源 客户端配置mirrors.repo文件,我们也可以使用Puppet的yumrepo资源来指定yum源 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 [root@master ~]# vim /etc/yum.repos.d/mirrors.repo [base] name=CentOS-$releasever - Base baseurl=http://mirrors.redking.com/centos/$releasever/os/$basearch/ enabled=1 gpgcheck=0 #released updates [updates] name=CentOS-$releasever - Updates baseurl=http://mirrors.redking.com/centos/$releasever/updates/$basearch/ enabled=1 gpgcheck=0 ? 1 2 3 4 5 [root@master ~]# cd /etc/yum.repos.d/ [root@master yum.repos.d]# mv CentOS-Base.repo CentOS-Base.repo.bak [root@master yum.repos.d]# yum clean all 安装Puppet 1.Puppet Master服务器端安装puppet-server,自动匹配安装Facter等相关依赖包 ? 1 2 3 4 5 [root@master ~]# yum install -y puppet-server [root@master ~]# chkconfig puppetmaster on [root@master ~]# service puppetmaster start 2.Puppet agent客户端安装puppet ? 1 2 3 4 5 [root@agent yum.repos.d]# yum install -y puppet [root@agent yum.repos.d]# chkconfig puppet on [root@agent yum.repos.d]# service puppet start =============================END===================================== 本文转自redking51CTO博客,原文链接:http://blog.51cto.com/redking/1612567,如需转载请自行联系原作者
本季目标 1、StringBuffer类 2、Runtime 类 3、包装类与JDK 1.5的新特性——泛型 4、日期的操作类 5、Math类 6、Random类 1、StringBuffer(重点) · String 类的时候说过:String 类的内容一旦声明则不可改变,改变的只是其地址。那么如果现在非要使用循环不断的修改String内容的时候,则就可以使用StringBuffer,也是一个字符串,但是可以修改。 · String类中的字符串连接使用的是“+”,而StringBuffer中的连接使用的是append()方法。 看下效果: 在内容会不断修改的时候使用StringBuffer比较合适。 现在再看下效果哈~ StringBuffer是不能直接转成String 类对象,必须调用toString()方法才可以把一个StringBuffer 的对象变为String类的对象。 2、Runtime表示运行时(了解) 在一个JVM中只有一个运行时,可以通过此类调用本机的一些程序。 此类中所有的构造方法对外部不可见,也就是说构造方法被私有化了,所以看不见。 单态 --> 在整个JVM中只能有一个运行时,所以其内部必然有一个方法可以取得Runtime对象。 public static Runtime getRuntime() 看下效果: Exec方法返回的是一个Process对象 看下效果:记事本打开三秒后自动关闭了哈~ 3、包装类 在JAVA 中提出了一种概念:一切皆对象,如果有此概念的话,则肯定有个矛盾点: 基本数据类型是对象吗?肯定不是,那么此时如果要符合之前的理论,则必须把基本数据类型进行包装。 看下效果:这就是典型包装类的使用哈~ 实际上包装类即可以把一个基本类型包装成对象,也可以把包装类变为基本数据类型。 Integer --> int:public int intValue()可以实现 看下效果: 以上的操作在 JDK 1.4之前都是这样做的,必须手工进行装箱或拆箱操作,而且包装类是不能直接进行++或—操作的。 在JDK 1.5之后提供了自动的装箱和拆箱操作,用户不用像之前那样必须直接调用方法完成了。 看下效果: 3、包装类与JDK 1.5的新特性——泛型 思考题: 现在要求实现一个坐标的操作类,有以下三种坐标: · 整数:x = 30 ; y = 50 · 小数:x = 30.3 ; y = 50.5 · 字符串:东经,北纬 考虑点: 对于用户而言,肯定只关心x和y的设置,你不能说让用户自己去选择设置整数或小数等。 以上问题我通过方法的重载做?我们验证一下使用方法的重载哈~ 此处就可以使用JDK 1.5提供的新功能 —— 泛型,在运行的时候由外部指定具体的操作类型。 4、日期的操作类 取得当前的日期 可以直接使用java.util.Date类完成。 打印的时间:Tue Mar 10 21:05:44 CST 2009 这样的时间看起来很别扭,不太符合我们中国人的习惯。一般直接使用此类的话,得到的时间不是很舒服,可以直接使用另外一个类——Calendar,此类可以把时间精确到毫秒。 Calendar是一个抽象类,如果是抽象类,则此处肯定使用其子类完成。 看下效果: 下面我们有选择滴进行删减哈~ (2)日期的格式化类 例如,现在有以下一个时间: 2009-3-10 21:18:30:345 将以上的时间格式显示为: 2009年3月10日 21点18分30 秒345毫秒 把之前的日期格式重新格式化了一下。 如果要完成上面的功能,则就可以使用SimpleDateFormart类,此类可以使用固定的模板把时间扣出来。 看下效果哈~ 5、Math类 数学操作类,但是在面试中里面有一个方法比较常见:round()方法,这个方法主要就是四舍五入哈~~~ 四舍五入的操作类 来看下效果哈~ 6、Random类,取得随机数 看下效果: #######################Michael分割线####################### 谨以此博文庆祝一下今天成为〓博客之星〓 #######################Michael分割线####################### 本文转自redking51CTO博客,原文链接:http://blog.51cto.com/redking/137834,如需转载请自行联系原作者
http://blog.sina.com.cn/s/blog_5007d1b10100o0v2.html 本文转自hblxp32151CTO博客,原文链接:http://blog.51cto.com/starpoint/585047,如需转载请自行联系原作者
C/S程序:表示的客户/服务器程序,每次需要编写两套程序 |- MSN、QQ:一般会有两套程序,一个是服务器端,另外一个是客户端 B/S程序:表示的浏览器/ 服务器,可以理解为动态WEB,论坛 本季目标 Sock:TCP通讯 数据报:UDP通讯 Socket程序需要的类: 1、所有的用户对于服务器来讲都是一个Socket客户端。 2、在服务器上使用ServerSocket类接收客户端的Socket Socket通信模型 Socket编程的四个基本步骤 编写一个服务器程序:ServerSocket 只要是网络连接都要求有一个端口 public ServerSocket(int port) public Socket accept() throws IOException 通过此方法等待客户端的socket进行访问。 ServerSocket01服务器端代码: 此服务器端的功能非常的简单,就是接收客户端的请求,之后在屏幕上输出哈~ Windows中有一个telnet命令,通过此命令就可以直接连接到服务器了。 客户端收到http://redking.blog.51cto.com字符串,同时服务器端显示“客户端回应完毕~~~” 只要是符合网络的协议标准,所有的客户端都可以连接到此服务器端上。 但是一般情况下,很少说直接去使用telnet连接,往往会编写一个客户端。 Socket public Socket(String host,int port) throws UnknownHostException,IOException 指定一个主机的IP地址和一个端口 ClientSocket01客户端代码: 验证下效果,和telnet一样哈~ 以上代码验证了,程序需要编写两套程序: · 一个是服务器端 · 另外一个是客户端 现在发现所有的代码只是执行一次就完了,那么能不能说执行多次呢?由我的用户可以自己发出中断的指令。 这样的做法我们可以做一个Socket经典 —— Echo程序 用户发什么内容,服务器就会回应什么内容: EchoServer代码: import java.io.*; import java.net.*; public class EchoServer{ //此处为了省去处理try...catch直接抛出了异常 public static void main(String args[]) throws Exception{ ServerSocket server = null; //输出肯定使用打印流 PrintStream out = null; //服务器肯定也要接收输入 BufferedReader buf = null; //1.实例化一个服务器的监听端 server = new ServerSocket(9999); //可以使用一种死循环的方式接收内容 Socket client = null; while (true){ //不断接收内容 client = server.accept(); //准备好向客户端输出内容 out = new PrintStream(client.getOutputStream()); //而且客户端要有输入给服务器端 buf = new BufferedReader(new InputStreamReader(client.getInputStream())); //下面先给出一个完整的信息提示 out.println("您好!欢迎光临:http://redking.blog.51cto.com"); out.println("输入bye表示退出哈~"); //一个用户要发很多的信息 while (true){ //接收客户端发送而来的内容 String str = buf.readLine(); if (str==null){ //如果str为空就表示退出 break; }else{ //如果输入的是bye则表示系统退出 if ("bye".equals(str)){ break; } //可以对用户发来的信息进行回应 out.println("ECHO:"+str); } } //进行收尾工作 out.close(); buf.close(); client.close(); //如果要关闭服务器时可以设置标志 //server.close(); } } } 看下效果: 现在我们用telnet连接上去看下效果 输入bye退出连接 同时可以多次连接 典型的包含了输入和输出 EchoClient代码: import java.io.*; import java.net.*; public class EchoClient{ public static void main(String args[]) throws Exception{ Socket client = null; BufferedReader buf = null; PrintStream out = null; //1.连接服务器 client = new Socket("localhost",9999); //接收服务器端的输入信息 buf = new BufferedReader(new InputStreamReader(client.getInputStream())); System.out.println(buf.readLine()); System.out.println(buf.readLine()); //之后准备从键盘接收数据 BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String userInput = null; out = new PrintStream(client.getOutputStream()); while ((userInput=in.readLine())!=null){ //表示有内容进来,要把内容发送到客户端 out.println(userInput); //接收服务器端的回应 System.out.println(buf.readLine()); } out.close(); in.close(); client.close(); } } 但是此程序有一个问题,即:当一个用户操作的时候,其他用户是不能操作的 程序是单线程的,所以每次只能一个用户访问。 此处如果想解决,则只能使用多线程进行操作。 首先需要编写一个线程的类: ThreadServer代码: import java.io.*; import java.net.*; public class ThreadServer implements Runnable{ //现在所有的Socket都要归入到一个线程之中 private Socket client = null; public ThreadServer(Socket client){ this.client = client; } public void run(){ //要不断的接收客户发送来的信息 String input = null; //通过BufferedReader进行接收 BufferedReader buf = null; //有一个输出的对象 PrintStream out = null; try{ buf = new BufferedReader(new InputStreamReader(this.client.getInputStream())); while(true){ //接收发送过来的信息 input = buf.readLine(); out = new PrintStream(this.client.getOutputStream()); if ("bye".equals(input)){ break; }else{ out.println("ECHO:"+input); } } this.client.close(); }catch (Exception e){} } } EchoServer01服务器端代码: import java.io.*; import java.net.*; public class EchoServer01{ //此处为了省去处理try...catch直接抛出了异常 public static void main(String args[]) throws Exception{ ServerSocket server = null; //输出肯定使用打印流 PrintStream out = null; //服务器肯定也要接收输入 BufferedReader buf = null; //1.实例化一个服务器的监听端 server = new ServerSocket(9999); //可以使用一种死循环的方式接收内容 Socket client = null; while (true){ //不断接收内容 client = server.accept(); //在此处启动了一个线程 new Thread(new ThreadServer(client)).start(); } } } 使用telnet测试效果哈~ 通过以上代码,可以发现,多线程实际上在服务器上是比较常用的。 服务器 = 多线程 + IO + Socket Socket程序实际上是属于TCP程序,是一个稳定的连接 UDP程序:数据报程序 Send发送端代码: import java.io.*; import java.net.*; public class Send{ public static void main(String args[]) throws Exception{ DatagramSocket ds = null; DatagramPacket dp = null; //发送端必须有一个监视的端口 ds = new DatagramSocket(9999); String str = "http://redking.blog.51cto.com"; //发送的内容只能是byte数组 //接收端端口号是8888 dp = new DatagramPacket(str.getBytes(),str.length(),InetAddress.getByName("localhost"),8888); ds.send(dp); ds.close(); } } 看下效果: 信息已经发送出去了哈~ 下面我们再写个接收代码 Receive接收端代码: import java.io.*; import java.net.*; public class Receive{ public static void main(String args[]) throws Exception{ DatagramSocket ds = null; DatagramPacket dp = null; //要有一个空间大小 byte b[] = new byte[1024]; //ds的监听端口就表示发送端指定好的 ds = new DatagramSocket(8888); dp = new DatagramPacket(b,b.length); //开始接收 ds.receive(dp); System.out.println(new String(dp.getData()).trim()); ds.close(); } } 现在我们测试一下哈~首先必须接收端开启着 然后我们运行发送端发送信息 总结 网络编程在实际中确实使用越来越少,JAVA的主要特点全部集中在了JAVA WEB上了。 只需要了解以下概念即可: · 网络程序的分类:TCP、UDP · 服务器 = IO + Socket + Thread ################################################### 本文转自redking51CTO博客,原文链接:http://blog.51cto.com/redking/135374,如需转载请自行联系原作者
症状:Outlook To-do-bar reminder无法使用,new task reminder设了时间的话会弹出提醒,但是如果是邮件选择Follow up的话,没有提醒,task在To-do-bar 栏下也见不到列表。尝试用outlook.exe /cleanreminders命令,重建outlook profile,重装outlook均无法解决 原因:未明 解决方法:重建windows profile后解决 本文转simmy51CTO博客,原文链接:http://blog.51cto.com/helpdesk/228160,如需转载请自行联系原作者
上季内容回顾: 字节流:InputStream、OutputStream 字符流:Reader、Writer 上季练习题: 既然是文件的拷贝,肯定要使用字节流,所以建立一个字节的输入流再建立一个字节的输出流,边读边写。 看下效果: IO操作就是研究五个类一个接口 · File类 · OutputStream、InputStream · Reader、Writer · 对象序列化 管道流 了解:管道流是管两个线程间通讯使的。 public void connect(PipedOutputStream src) throws IOException 把输出与输入连接在一起。 import java.io.*; //设置两个线程,一个发送另一个接收 class Send implements Runnable{ private PipedOutputStream out = null; //在构造方法中实例化此对象 public Send(){ this.out = new PipedOutputStream(); } public void run(){ //启动线程,启动线程时直接发送 String str = "Hello World~~~"; try{ this.out.write(str.getBytes()); }catch (Exception e){} } //必须把管道输出流返回去 public PipedOutputStream getOut(){ return this.out; } } class Receive implements Runnable{ private PipedInputStream input = null; public Receive(){ this.input = new PipedInputStream(); } public void run(){ //启动线程,接收内容 byte b[] = new byte[1024]; int len = 0; try{ len = this.input.read(b); this.input.close(); System.out.println(new String(b,0,len)); }catch (Exception e){} } public PipedInputStream getInput(){ return this.input; } } public class IODemo01{ public static void main(String args[]){ Send s = new Send(); Receive r = new Receive(); //要把输出连接到输入上去哈~ try{ r.getInput().connect(s.getOut()); }catch (Exception e){} new Thread(s).start(); new Thread(r).start(); } } 看下效果: ByteArrayInputStream 内存的输入、输出流 之前讲解的很多内容都是把内容直接输出到文件中去了,那么现在把内容输入到内存中,直接从内存中输出。 看下有没变成大写哈~ 应该按以下的方式理解: · ByteArrayInputStream():理解为内存要读取 · ByteArrayOutputStream():从内存中输出 输入输出方法 System.out: |- PrintStream是一个打印流,表示提供了更好的打印操作。 PrintStream有那些好处呢? PrintStream是OutputStream的子类 实际上在IO中体现了一种设计模式 —— 装饰模式。 · 发现在OutputStream中的功能虽然可以输出,但是输出的过程不太好操作,因为所有的内容都要向byte数组转换。 PrintStream的基本原理 PrintStream 中提供了比OutputStream 中更多的打印功能,可以输出任意的数据,也可以对输出的数据进行换行的处理。 看下效果:在屏幕上换行是\n就可以了,在文件中换行是\r\n。 现在既然已经知道了PrintStream是OutputStream的对象,那么问?是否可以通过OutputStream完成向屏幕上输出的功能呢?可以使用对象多态性哈~~~ PrintStream 是一个字节的打印流,与它类似的还有一个PrintWirter字符的打印流,建议使用字节打印流是比较方便。 总结 1、System.out与OutputStream的关系 2、PrintStream实际上是JAVA装饰模式的应用,具有比父类提供更多更方便的功能 #################################################### 本文转自redking51CTO博客,原文链接:http://blog.51cto.com/redking/133816,如需转载请自行联系原作者
Objective: Verify that the extended access lists created in Lab 29 are configured correctly.Lab Equipment: Router 1, Router 2, and Router 4 from the eRouters menuBackground Reading: Lab Primer Lesson 10: Access ListsPrerequisite: You must have just completed Lab 29: Extended Access Lists in order to complete this lab successfully.1. Test whether the extended access lists created in Lab 29 are working properly. Connect to Router4, and try to ping Router1’s serial 0 interface. If the access lists are configured correctly, you should not be able to ping the serial interface.Router4>enable Router4#ping 24.17.2.17 2. Now that you have verified that the access lists are blocking pings to Router1 from the subnet off of Router1’s serial 0 interface, verify that Telnet traffic from that subnet is allowed to reach Router1. Connect to Router1, enable Telnet access, and then set the password to boson.Router1(config)# Router1(config)#line vty 0 4 Router1(config-line)#login Router1(config-line)#password boson Router1(config-line)#exit 3. Connect to Router4 again, and try to telnet into Router1’s serial 0 interface.Router4#telnet 24.17.2.17 4. If Telnet access is permitted, you should see the host name in the router prompt change to Router1. Now, press the CTRL+SHIFT+6 key combination followed by the X key to return to Router4. Then type disconnect 1 to close the connection to Router1.Router1> Press CTRL+SHIFT+6, then press X Router4#disconnect 1 5. Connect to Router2, and see if you can ping Router4’s serial 0 interface.Router2>enable Router2#ping 24.17.2.18 Consider why the ping is unsuccessful. The packet starts at Router2, travels through Router1, and reaches Router4. Once it arrives at Router4, it is repackaged and sent back to Router1. When Router4 repackages the packet, the packet’s source IP address becomes the destination IP address, and the destination IP address becomes the source IP address. When the packet encounters the access list on Router1’s serial 0 interface, it is blocked because the packet’s source IP address is Router4’s serial 0 address. 6. See if you can ping Router1’s Ethernet 0 interface from Router2.Router2#ping 24.17.2.1 7. Now, try to telnet into Router1’s Ethernet 0 interface from Router2. If Telnet access is permitted, you should see the host name in the router prompt change to Router1. Press the CTRL+SHIFT+6 key combination followed by the X key to return to Router4. Then type disconnect 1 to close the connection to Router1.Router2#telnet 24.17.2.1 Router1> Press CTRL+SHIFT+6, then press X Router2#disconnect 1 8. To verify that the access lists are configured on the interfaces, display the running configuration.Router1#show running-config 9. You can also view which access lists are applied to the interfaces by using the show IP interface command.Router1#show ip interface 10. The show access-lists command displays which access lists have been created on a router. The output of this command also tells you which lines of the access list have been used and how many packets have been permitted or denied.Router1#show access-lists ******************************************************** Above:CCNA(Stand-ALONE)Lab 29-Extended Access Lists Next:CCNA(Stand-ALONE)Lab 31-Named Access Lists 本文转自redking51CTO博客,原文链接:http://blog.51cto.com/redking/74777,如需转载请自行联系原作者
本季目标 Java的反射机制 工厂模式综合讲解 1、什么叫反射 Java.lang.reflect包下 正常情况下我们可以通过类实例化一个对象,那么通过反射实际上就可以通过一个对象得到此类完整的包.类名称。 package org.michael; class Person{ private String name; private int age; public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age; } public String getName(){ return this.name; } public int getAge(){ return this.age; } } public class Demo01{ public static void main(String args[]){ Person p = new Person(); //假设现在不知道p是那个类的对象,则可以通过反射机制找到 Class c = null; c = p.getClass(); System.out.println(c.getName()); } } 看下效果: 除了可以找到对象所在的包.类名称,实际上也可以把所有的方法名称列出来。 package org.michael; import java.lang.reflect.*; class Person{ private String name; private int age; public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age; } public String getName(){ return this.name; } public int getAge(){ return this.age; } } public class Demo02{ public static void main(String args[]){ Person p = new Person(); //假设现在不知道p是那个类的对象,则可以通过反射机制找到 Class c = null; c = p.getClass(); Method m[] = c.getMethods(); for(int i=0;i<m.length;i++){ System.out.println(m[i]); } } } 2、研究Class类 Class类的构造方法被私有化了,外部无法直接看见,所以其内部必然有一个方法可以取得Class 实例。 public static Class<?> forName(String className) throws ClassNotFoundException 此方法可以返回Class类的实例,此方法接收一个完整的包.类名称。 通过newInstance方法,可以将传入的完整的字符串(包.类名称)实例化。 package org.michael; import java.lang.reflect.*; class Person{ private String name; private int age; public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age; } public String getName(){ return this.name; } public int getAge(){ return this.age; } } public class Demo03{ public static void main(String args[]){ Person p = null; Class c = null; try{ c = Class.forName("org.michael.Person"); }catch (Exception e){} try{ p = (Person)c.newInstance(); }catch (Exception e){} //上面两行代码也可以使用下面一行代码取代哈~ // p = (Person)Class.forName("org.michael.Person").newInstance(); p.setName("Michael"); p.setAge(30); System.out.println(p.getName()+"--->"+p.getAge()); } } 如果要使用以上的代码去实例化一个对象,则必须有一个前途条件:在对象所在的类中必须有一个无参构造方法,如果没有此无参构造,则肯定会出现错误。 package org.michael; import java.lang.reflect.*; class Person{ private String name; private int age; public Person(String name,int age){ this.name = name; this.age = age; } public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age; } public String getName(){ return this.name; } public int getAge(){ return this.age; } } public class Demo04{ public static void main(String args[]){ Person p = null; Class c = null; try{ c = Class.forName("org.michael.Person"); p = (Person)c.newInstance(); }catch (Exception e){ System.out.println(e); } System.out.println(p.getName()+"--->"+p.getAge()); } } 在此时如果想继续通过此操作为对象进行实例化,则可以通过构造方法类(Constructor)完成。 package org.michael; import java.lang.reflect.*; class Person{ private String name; private int age; public Person(String name,int age){ this.name = name; this.age = age; } public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age; } public String getName(){ return this.name; } public int getAge(){ return this.age; } } public class Demo05{ public static void main(String args[]){ Person p = null; Class c = null; try{ c = Class.forName("org.michael.Person"); Constructor[] cs = c.getConstructors(); Object obj[] = new Object[]{"Michael",30}; //一个类中会有多个构造方法,所以此时返回一个数组 p = (Person)cs[0].newInstance(obj); }catch (Exception e){ System.out.println(e); } System.out.println(p.getName()+"--->"+p.getAge()); } } 反射机制实际上是我们所有框架的一个基础,那么现在就利用反射机制完成一个高可扩展性的工厂设计。 回顾:工厂设计 interface Fruit{ public void grow(); public void eat(); } class Apple implements Fruit{ public void grow(){ System.out.println("苹果在生长..."); } public void eat(){ System.out.println("吃苹果..."); } } class Orange implements Fruit{ public void grow(){ System.out.println("橘子在生长..."); } public void eat(){ System.out.println("吃橘子..."); } } class Factory{ public static Fruit getFruit(int i){ Fruit f = null; if (i==1){ f = new Apple(); } if (i==2){ f = new Orange(); } return f; } } public class Demo06{ public static void main(String args[]){ Fruit f = Factory.getFruit(1); f.grow(); } } 客户端只与工厂和直接的接口有关了,而与其他的无关,但是有个问题,如果现在要扩展了子类,则工厂也必须同时进行修改。那么有没有一种方法,可以让子类扩充之后不去修改工厂呢?肯定是有的,通过Class.forName 完成。 interface Fruit{ public void grow(); public void eat(); } class Apple implements Fruit{ public void grow(){ System.out.println("苹果在生长..."); } public void eat(){ System.out.println("吃苹果..."); } } class Orange implements Fruit{ public void grow(){ System.out.println("橘子在生长..."); } public void eat(){ System.out.println("吃橘子..."); } } class Banana implements Fruit{ public void grow(){ System.out.println("香蕉在生长..."); } public void eat(){ System.out.println("吃香蕉..."); } } class Factory{ public static Fruit getFruit(String className){ Fruit f = null; try{ f = (Fruit)Class.forName(className).newInstance(); }catch (Exception e){} return f; } } public class Demo07{ public static void main(String args[]){ Fruit f = Factory.getFruit("Banana"); f.grow(); } } 但是此程序依然有一个缺点,现在的输入的包.类名称实际上长度非常的短,如果包.类名称的长度过长了,则在使用的时候就比较麻烦了。所以最好可以找个代号进行替代。 使用Hashtable的子类 —— Properties完成。 import java.util.*; import java.io.*; interface Fruit{ public void grow(); public void eat(); } class Apple implements Fruit{ public void grow(){ System.out.println("苹果在生长..."); } public void eat(){ System.out.println("吃苹果..."); } } class Orange implements Fruit{ public void grow(){ System.out.println("橘子在生长..."); } public void eat(){ System.out.println("吃橘子..."); } } class Banana implements Fruit{ public void grow(){ System.out.println("香蕉在生长..."); } public void eat(){ System.out.println("吃香蕉..."); } } class Factory{ public static Fruit getFruit(String className){ Fruit f = null; try{ f = (Fruit)Class.forName(className).newInstance(); }catch (Exception e){} return f; } } class InputData{ private BufferedReader buf = null; public InputData(){ this.buf = new BufferedReader(new InputStreamReader(System.in)); } public String getString(){ String str = null; try{ str = this.buf.readLine(); }catch (Exception e){} return str; } } public class Demo08{ public static void main(String args[]){ Properties p = new Properties(); p.setProperty("a","Apple"); p.setProperty("o","Orange"); p.setProperty("b","Banana"); System.out.println(p); System.out.print("请选择所需要的类型:"); String str = new InputData().getString(); //进一步扩展,现在可以由用户自己输入要使用的类型 Fruit f = Factory.getFruit(p.getProperty(str)); f.grow(); } } 如果现在再增加子类呢? 属性文件肯定不够了。 所以此时为了达到好的效果,则最好可以将属性保存起来,之后通过修改保存的文件达到属性的扩充。 import java.util.*; import java.io.*; interface Fruit{ public void grow(); public void eat(); } class Apple implements Fruit{ public void grow(){ System.out.println("苹果在生长..."); } public void eat(){ System.out.println("吃苹果..."); } } class Orange implements Fruit{ public void grow(){ System.out.println("橘子在生长..."); } public void eat(){ System.out.println("吃橘子..."); } } class Banana implements Fruit{ public void grow(){ System.out.println("香蕉在生长..."); } public void eat(){ System.out.println("吃香蕉..."); } } class Factory{ public static Fruit getFruit(String className){ Fruit f = null; try{ f = (Fruit)Class.forName(className).newInstance(); }catch (Exception e){} return f; } } class PropertyOperate{ private Properties pro = null; public PropertyOperate(){ this.pro = new Properties(); this.load(); } //设置一个返回方法 public Properties getPro(){ return this.pro; } //从文件中读出属性,如果文件不存在,则创建一个默认的 private void save(){ pro.setProperty("a","Apple"); pro.setProperty("o","Orange"); //保存在文件之中 try{ pro.storeToXML(new FileOutputStream(new File("e:\\fruit.xml")),"FRUIT FACTORY"); }catch (Exception e){} } private void load(){ File f = new File("e:\\fruit.xml"); if(f.exists()){ //文件存在则可以读取 try{ pro.loadFromXML(new FileInputStream(f)); }catch (Exception e){} }else{ //进行创建 this.save(); } } } class InputData{ private BufferedReader buf = null; public InputData(){ this.buf = new BufferedReader(new InputStreamReader(System.in)); } public String getString(){ String str = null; try{ str = this.buf.readLine(); }catch(Exception e){} return str; } } public class Demo09{ public static void main(String args[]){ Properties p = new PropertyOperate().getPro(); System.out.println(p); System.out.print("请选择所需要的类型:"); String str = new InputData().getString(); //进一步扩展,现在可以由用户自己输入要使用的类型 Fruit f = Factory.getFruit(p.getProperty(str)); f.grow(); } } 如果此时要想新增加可以操作的子类,则就需要配置fruit.xml文件即可。 此种代码是典型的配置与程序相分离,程序直接有配置文件有关。某一个部分的修改不影响其他程序。—— 思想必须建立起来。 总结 对象的产生到底有多少种方法了: · 直接用new关键字产生:直接,但是代码间会产生严重的耦合性 · 可以通过工厂传递引用:直接,但是必须考虑到代码以后的可维护性 · 通过对象克隆可以完成 · 通过Class.forName()进行反射加载完成。 ####################Michael分割线###################### 本文转自redking51CTO博客,原文链接:http://blog.51cto.com/redking/141195,如需转载请自行联系原作者
一、编程语言与操作系统: 应用程序 ____________________ |lib call | | |-------------------| |system call | |———————————----————| |各种硬件 | ————————————————————| API:application program interface ABI:application binary interface Api应用层级兼容,未必abi层次也兼容,有些程序对二进制的识别格式是不相同的 UNix-like:ELF格式的程序 windows:exe,msi linux:wine模拟windows库 windows:Cywin虚拟出linux运行环境 系统级开发:C/C++:httpd,vsftpd,nginx go编程语言:新贵 C/C++编程依赖于系统上的标准库 应用级开发:java/Python/perl/ruby/php java:hadoop,hbase,(jvm)运行环境 Python:openstack 云管理平台,(pvm) perl:(perl)perl的解释器 ruby:(ruby)解释器/虚拟机{运行环境} php:(php) //一般解释器或者虚拟机{jvm,pvm} 使用C/C++编写 php:世界上最好的语言 c/C++程序格式: 源代码:文本格式的程序代码 编译开发环境:编译器、头文件、开发库 二进制格式:文本格式的代码-->编译器-->二进制格式(二进制程序、库文件、配置文件) java/python 源代码:编译成能够在其虚拟机(jvm/pvm)上运行的格式 开发环境:编译器、开发库 二进制: 项目构建工具://不再需要考虑程序编译主次关系,由项目构建关系负责,项目构建工具借助于配置文件实现 c/c++:make java:maven 程序包管理器: 源代码 --> 目标二进制格式 -->组织成为一个或有限几个“包”文件; 安装、升级、卸载、查询、校验等操作 程序包管理器: debian:kali,ubuntu //dpt,dpkg , ".deb" redhat:rhel,centos,fedora //redhat package manager,rpm , ".rpm" //perl-C现在使用的是C语言写的 //rpm:rpm is package manager;成为标准 slckware:S.u.S.E: //rpm,suse的rpm和rhel的是不兼容的,suse为rpm开发了一个重要的库,后期被rhel收纳 //rpm:".rpm" 命令rpm Gentoo: //采用了freebsd的机制,ports的包机制 Archlinux //轻量级, 源代码:name-VERSION.tar.[xz,gz,bz2] VERSION:major-minor-release major:重大改变 minor:局部改变 release:修复bug,小串代码改变 rpm包命令格式: vsftpd-3.0.2-10.el7.x86_64.rpm name-VERSION-release.arch.rpm release:是制作rpm包的次数 VERSION.release是源代码的release arch:architecture:i386,x64(amd64),ppc(powerpc),noarch(通用平台) i386:支持较老版本的32bit cpu i686:支持较新版本的32bit cpu 拆包: redis-3.0.2.tar.gz--> redis.3.0.2-1.el7.x86_64 //把一个包的多种功能,拆成多个部分,按需组织rpm包 //主包和分支包 主包:name-VERSION-release.arch.rpm 支包:name-function-VERSION-release.arch.rpm function:devel,utils(工具程序),libs,plugins(插件) 依赖关系:每个程序包的功能都很简单,包之间存在很复杂的依赖关系 x,y,z x-->y,z y-->a,c,b c-->Y 前端工具:自动解决依赖关系 yum:rpm包管理器的前端工具 apt-get(apt-cache):deb包 zypper:suse上的rpm包管理器 dnf:Fedora 22+ 系统上的rpm包管理器的前端工具 程序包管理: 功能:将编译好的应用程序的各组成文件打包成一个或几个程序包文件,从而更方便地实现程序包的安装、升级、卸载和查询等操作 1.程序包的组成清单(每个程序包单独实现) 文件清单 安装或卸载时运行的脚本 2.数据库(公共) 程序包的名称和版本 依赖关系 功能说明 安装生成的各文件路径及校验码信息 /var/lib/rpm/ rpm数据库所在 二、获取程序包的途径: 1.系统发行版的光盘或者官方的文件服务器 http://mirrors.aliyun.com http://mirrors.sohu.com http://mirrors.163.com 2.项目官方站点 apache官网:www.apache.org zabbix:www.zabbix.com 3.第三方组织 (a)EPEL: mirrors.aliyun.com/epel/7/x86_64 (b)搜索引擎 pkgs.org rpmfind.net rpm.pbone.net 4.自己动手,丰衣足食 建议:校验,检查其合法性 来源合法性: 程序包的完整性:三、Centos上rpm命令管理程序包(1)安装 安装,升级,卸载,查询和校验,数据库维护 rpm {-i|--install} [install-options] PACKAGE_FILE ... -i :install -v verbose通用选项,显示过程 -vv 更详细 -h 以hash输出进度条 --test 仅仅是检查一下,测试不安装 --nodeps //忽略依赖关系,no dependce --replacepkgs //替代安装 --noscripts //有些程序包安装过程中,可能需要运行一段自带脚本, rpm可以自带脚本: 四类: preinstall:安装之前,%pre postinstall:安装完成之后,%post preuninstall:卸载开始前,%preun postuninstall :卸载完成之后,%postun --noscripts --nopre --nopost --nopreun --nopostun --nosignature //来源合法性,不检查包签名信息 --nodigest //不检查包完整幸信息,头文件摘要 -U :update,-F --freshen//使更新 -e :--erase -q:--query -l :list生成文件 -V:--verify校验 数据库维护: --builddb,--initdb (2)升级 -U update Uvh /Fvh rpm {-U|--upgrade} [install-options] PACKAGE_FILE ... //和安装一样 -U 升级或者安装,有没有老版本,都会安装 -F 升级,有老版本才会安装 --oldpackage :降级安装老的程序包,不兼容 --force:强制升级 其他和rpm -ivh 一样 注意: (1)不要对内核做升级操作,更新内核需要重启系统 //linux支持多内核版本并存,因此,直接安装新版本内核即可 (2)如果某源程序包的配置文件,安装后曾被修改过,升级时,新版本的程序提供的同一个配置那文件不会覆盖原有的 配置文件,而是把新版本的配置文件,重命名后(filename.rpmnew)后,提供 (3)卸载 -e --allmatches //假如存在多版本的话,多版本一并删除 --nodeps //忽略依赖关系 --test //dry run 仅仅测试 --noscripts //不执行脚本 rpm -e zsh //pack_name zsh即可,数据库中有文件保存 rpm -ivh 文件名 (4)查询 rpm {-q|--query} [select-options] [query-options] -q zsh //查询指定包zsh是否安装 select-options: -a,--all 不加选项,查询所有已经安装的包 rpm -qa |grep zsh -f /etc/fstab 查询文件的安装包 -g,--group 组名//查询指定包组中包含的包 -p,--packaeg package_file:实现查看未安装包的,结合query-optionss实现 rpm -qpl zsh-5.0.2-14.el7.x86_64.rpm //查询未安装程序包的安装能够生成文件 --wahtprovice CAPABILITY//查询提供某种能力的包 rpm -q --whatprovide 'config(bash)' --whatrequires CAPABLITY //查询指定的CAPABILITY被哪个程序包所依赖 query-options --changelog //查询rpm包的changelog,不是源码的 rpm -q --changelog zsh //查看zsh的改进日志 -l,--list //程序包安装生成的所有文件列表 rpm -ql zsh -i info,查询程序包相关信息,版本号,大小,所属的包组,等 rpm —qi bash -c ,--configfiles:查询指定的程序包的配置文件 rpm -qc bash -d,--docfile :查询指定的程序包的帮助文档 rpm -qd bash --provides:列出指定的程序包提供的CAPABILITY rpm -q --provides bash //bash提供的 rpm -q --whatprovides 'config(bash)' -R requires//查询指定程序包的所依赖的程序包 rpm -qR bash --scripts //查询脚本 rpm -q --scripts bash rpm -qp --scripts zsh-5.0.2-14.el7.x86_64.rpm ql,qf,qc,qi,qd //qf文档的产生源(5)校验 rpm {-V|--verify} [select-options] [verify-options] -V //rpm -V zsh //安装完成后,校验 1 2 3 4 5 6 7 8 9 S file Size differs M Mode differs (includes permissions and file type) 5 digest (formerly MD5 sum) differs D Device major/minor number mismatch L readLink(2) path mismatch U User ownership differs G Group ownership differs T mTime differs P caPabilities differ rpm -ql zsh //随意修改其中一个文件 rpm -V zsh //就能看到效果 select-options:和查询的select-options一样 -a,-f,-g,-p verify-options: --nodeps 不校验依赖 --nodigest 不校验包头, --noscripts 不检查脚本 --nofiles 不检查 --nosignature 不检查包头签名信息 //默认检查所有属性 rpm -V --nofiles zsh(6)包来源合法性验证和完整性验证 来源合法性验证: 数字签名:非对称加密:一个公钥,一个私钥 包的制作者, 1.首先使用单项加密,计算出包的特征码,定长输出 2.然后再用自己的私钥加密特征码,这叫数字签名 , 3.把加密后的特征码附加到包后 //只要拿到公钥,就能解密 中间者:能够解密特征码,因为能拿到对方公钥,但是不能再次加密,因为没有作者的私钥 //用户拿到作者的公钥,进行解密特征码,解密成功,则认为来源合法 //我用同样的方法,进行单项加密计算特征码,一样则证明包内容没有修改过//完整性 如何拿到对方的公钥: 1.从网上下载,不可靠 2.互联网上是使用CA来实现,可靠手段拿到对方公钥 rpm --import /mnt/RPM-GPG-KEY-CentOS7 //导入公钥 /etc/pki/rpm-gpg/ 导入到此地 对于CentOS发行版:rpm --import rpm -ivh zsh-***** //自动进行校验操作 rpm -K zsh-5.03..... //手动验证 验证: 安装此组织签名的程序时,会自动执行验证 手动验证:rpm -K PACKAGE_FILE 1 数字签名:保证来源合法性和数据完整性(7)数据库重建 rpm管理数据库路径:/var/lib/rpm/ 查询操作:就是基于该数据库查询 Centos6:man rpm //rpm --initdb|--rebuilddb Centos7:man rpmdb rpmdb --initdb 初始化db,当前无任何数据库时创建一个新的,当前有,不执行任何操作 --rebuildb 重建db,重新构建,通过读取当前系统上所有已经安装过的程序包进行重新创建 --dbpath 指定db路径 rpmdb --initdb --dbpath=/tmp/rpm 四、rpm命令小结 linux程序包管理器,rpm包管理器 1 2 3 4 5 6 7 安装:rpm -ivh ,--nodeps,--replacepkgs 卸载:-e,--nodeps 升级:-U|-F vh //F只用于升级,--nodeps,--oldpackage 查询:-q,-a,f,i,qd,qc,--script,changelog,provides/whatprovides,requires/whatrequires 校验:-V, 验证合法性:--import,-K手动验证,--nodigest,--nosignature 数据库重建:rpmdb --initdb --rebuilddb 本文转自MT_IT51CTO博客,原文链接:http://blog.51cto.com/hmtk520/1950170,如需转载请自行联系原作者
No.1 光模块是如何分类的,类型有哪些? 按速率分类 为了满足各种传输速率的需求,产生了不同速率的光模块:FE光模块、GE光模块、10GE光模块、40GE光模块。 按封装分类 传输速率越高的光模块,结构越复杂。为了满足不同结构的需求,产生了各种封装类型的光模块。华为交换机适用的封装类型有:SFP封装、SFP+封装、XFP封装、QSFP+封装。 SFP(Small Form-factor Pluggable)光模块:小型可插拔型封装。SFP光模块支持LC光纤连接器,支持热插拔。 eSFP(Enhanced Small Form-factor Pluggable)光模块:增强型SFP,有时也将eSFP称为SFP。指的是带电压、温度、偏置电流、发送光功率、接收光功率监控功能的SFP。 SFP+(Small Form Pckage Plus)光模块:指速率提升的SFP模块,因为速率提升,所以对EMI敏感,壳子上面的裙片做的多了,配对的笼子也相对缩紧了。 XFP(10-GB Small Form-factor Pluggable)光模块:“X”是罗马数字10的缩写,所有的XFP模块都是10G光模块。XFP光模块支持LC光纤连接器,支持热插拔。相比SFP+光模块,XFP光模块尺寸更宽更长。 QSFP+(Quad Small Form-Factor Pluggable)光模块:四通道小型可热插拔光模块。QSFP+光模块支持MPO光纤连接器,相比SFP+光模块尺寸更大。 按物理层标准分类 为了满足数据能以不同的形式传输,定义了各种不同的物理层标准,产生了支持各种标准的光模块。 按模式分类 光纤分为单模光纤、多模光纤。为了满足使用不同类别的光纤,产生了单模光模块、多模光模块。 单模光模块与单模光纤配套使用。单模光纤传输频带宽,传输容量大,适用于长距传输。 多模光模块与多模光纤配套使用。多模光纤有模式色散缺陷,其传输性能比单模光纤差,但成本低,适用于较小容量、短距传输。 No.2 如何判断光模块是单模还是多模? 根据光纤的纤芯直径及特性分为多模和单模。一般多模光纤纤芯直径大,模式色散严重,所以用于短距离的信号传输;而单模光纤模式色散小,所以一般用于长距离的信号传输。多模光纤的光纤直径的为62.5um和50um;单模光纤的光纤直径为9um。 在光模块信息中,传输距离显示“Transfer Distance(m) :500(50um),300(62.5um)”该信息中,50um或62.5um表示光纤直径,因此表示该光模块为多模光模块,如果显示为9um,则表示为单模光模块。 No.3 如何查看光模块的序列号? 序列号,是模块的身份标识,唯一编码,光模块的制造信息中的“Manu. SerialNumber :PEP3L5D”即表示光模块的序列号。 No.4 如何判断光模块是不是华为认证的光模块? 光模块的常规信息和制造信息中的“Vendor Name :FINISAR CORP.”即光模块的厂商信息。如果该信息显示内容为“Vendor Name :HUAWEI”,则表示该光模块为华为认证的光模块。 No.5 使用非华为认证光模块有什么影响? 华为交换机认证光模块时,对光模块功能进行了全面的验证,有效的保证了光模块的质量。验证项目包括插拔验证、收发光功率验证、信号传输质量验证、基本信息读取验证、容错性验证、兼容性验证、EMC验证、环境性能验证等。 ▎使用非认证光模块时,导致的常见问题如下: 光模块结构问题,导致光模块无法插入光接口。 一些非认证光模块在结构尺寸方面不满足MSA协议,当一个光接口上插入了该类光模块后,由于光模块的尺寸问题,与该接口相邻的接口都无法插入光模块。 光模块数据总线问题,导致设备数据总线挂死。 一些非认证光模块在数据总线设计方面存在问题,当使用该类光模块时,就会导致对应设备数据总线挂死,挂死在该数据总线上的数据无法再读出。 光模块金手指尺寸不合理,导致接口的电子元器件损伤。 一些非认证光模块的金手指尺寸不合理,当使用该类光模块时,就会导致接口内的电路短路,损伤接口电子元器件。 光模块温度监控不规范,导致错误告警。 一些非认证光模块的温度监控系统不符合业界规范,读取的温度值偏高,导致系统上报错误的温度告警。 光模块寄存器设置不合理,导致参数、诊断信息读取错误或无法读取。 一些非认证光模块的A0页寄存器设置不合理,导致数据总线读取参数、诊断信息时,读取的信息错误或者无法读取信息。 光模块设计不满足EMC,其自身抗电磁干扰能力低,并给周围的设备带来电磁干扰。 光模块工作温度范围不符合要求,导致在高温时光功率降低,业务中断。 No.6 光模块发送功率、接收功率异常(过高、过低)、使用了非华为认证光模块的告警形式有哪些? No.7 光模块光功率过高如何处理? 可以在光模块上增加光衰,使光功率衰减到合适的范围内。 No.8 光模块光功率过低如何处理? 处理步骤请参见故障处理手册“硬件故障-接口故障”中的“光接口对接,设备出现光功率告警”。 No.9 为什么有时候看不到光模块的光功率的信息? ▎可能的主要原因有: 使用的是非华为认证的光模块,不兼容,无法读取光模块信息。 使用的是非增强型光模块,没有告警信息Alarm information和诊断信息Diagnostic information。 光模块硬件故障。 转自《交换机在江湖之维护宝典合集》,有删改 本文转自Grodd51CTO博客,原文链接:http://blog.51cto.com/juispan/1947955,如需转载请自行联系原作者
Rsync命令是一个远程数据同步工具,可通过网络快速同步多台主机间的文件。它在同步文件的同时,可以保持原来文件的权限、时间、软硬链接等附加信息,也可以做增量的拷贝。支持通过ssh方式来传输文件,这样其保密性会非常好。rsync备份主要分为三种方式,一是本地到本地的备份,二是本地到网络的备份,三是网络到本地的备份。 ▎命令格式: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Local: rsync [OPTION...] SRC... [DEST] ##拷贝本地文件。当SRC和DES路径信息都不包含有单个冒号":"分隔符时就启动这种工作模式。如:rsync -a /data /backup Access via remote shell: Pull: rsync [OPTION...] [USER@]HOST:SRC... [DEST] Push: rsync [OPTION...] SRC... [USER@]HOST:DEST ##使用一个远程shell程序(如rsh、ssh)来实现将远程机器的内容拷贝到本地机器。当SRC地址路径包含单个冒号":"分隔符时启动该模式。如:rsync -avz foo:src/bar /data ##使用一个远程shell程序(如rsh、ssh)来实现将本地机器的内容拷贝到远程机器。当DST路径地址包含单个冒号":"分隔符时启动该模式。如:rsync -avz *.c foo:src Access via rsync daemon: Pull: rsync [OPTION...] [USER@]HOST::SRC... [DEST] rsync [OPTION...] rsync://[USER@]HOST[:PORT]/SRC... [DEST] Push: rsync [OPTION...] SRC... [USER@]HOST::DEST rsync [OPTION...] SRC... rsync://[USER@]HOST[:PORT]/DEST ##从远程rsync服务器中拷贝文件到本地机。当SRC路径信息包含"::"分隔符时启动该模式。如:rsync -av root@192.168.78.192::www /databack ##从本地机器拷贝文件到远程rsync服务器中。当DST路径信息包含"::"分隔符时启动该模式。如:rsync -av /databack root@192.168.78.192::www Usages with just one SRC arg and no DEST arg will list the source files instead of copying. ##列远程机的文件列表。这类似于rsync传输,不过只要在命令中省略掉本地机信息即可。如:rsync -v rsync://192.168.78.192/www ▎常用选项: 选项 作用 -a 包含-rtplgoD -r 同步目录时要加上,类似cp时的-r选项 -v 同步时显示一些信息,让我们知道同步的过程 -l 保留软连接 -L 加上该选项后,同步软链接时会把源文件给同步 -p 保持文件的权限属性 -o 保持文件的属主 -g 保持文件的属组 -D 保持设备文件信息 -t 保持文件的时间属性 --delete 删除DEST中SRC没有的文件 --exclude 过滤指定文件不同步 -P 显示同步过程,比如速率,比-v更加详细 -u 加上该选项后,如果DEST中的文件比SRC新,则不同步 -z 传输时压缩 测试示例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 本地到本地备份: [root@juispan ~]# rsync -aP /tmp/bigfile /usr/local/ sending incremental file list bigfile 106070960 100% 30.24MB/s 0:00:03 (xfer#1, to-check=0/1) sent 106083984 bytes received 31 bytes 30309718.57 bytes/sec total size is 106070960 speedup is 1.00 本地到网络备份: [root@juispan ~]# rsync -av /tmp/bigfile 192.168.137.200:/tmp/ ##接收端也要安装rsync工具 bash: rsync: 未找到命令 rsync: connection unexpectedly closed (0 bytes received so far) [sender] rsync error: remote command not found (code 127) at io.c(605) [sender=3.0.9] [root@juispan ~]# rsync -av /tmp/bigfile 192.168.137.200:/tmp/ sending incremental file list bigfile sent 106083984 bytes received 31 bytes 7316138.97 bytes/sec total size is 106070960 speedup is 1.00 [root@juispan ~]# ll /tmp/bigfile -rw-r--r--. 1 root root 106070960 7月 20 09:34 /tmp/bigfile [root@server02 tmp]# ll bigfile -rw-r--r--. 1 root root 106070960 7月 20 09:34 bigfile ##目标端查看信息完全一致 网络到本地备份: [root@juispan ~]# rsync -av 192.168.137.200:/tmp/bigfile / receiving incremental file list bigfile sent 30 bytes received 106083989 bytes 6844130.26 bytes/sec total size is 106070960 speedup is 1.00 ▎通过ssh方式同步: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 [root@juispan ~]# rsync -av /tmp/ 192.168.137.200:/tmp/ sending incremental file list ./ bigfile py.py yum_save_tx.2017-07-20.09-37.LxNivf.yumtx sent 106085634 bytes received 77 bytes 7858200.81 bytes/sec total size is 106072339 speedup is 1.00 [root@juispan ~]# rsync -av -e "ssh -p 22" /tmp/bigfile 192.168.137.200:/tmp/ sending incremental file list sent 33 bytes received 12 bytes 3.91 bytes/sec total size is 106070960 speedup is 2357132.44 ▎通过服务的方式同步: ①编辑配置文件/etc/rsyncd.conf 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 [root@juispan ~]# cat /etc/rsyncd.conf # /etc/rsyncd: configuration file for rsync daemon mode # See rsyncd.conf man page for more options. # configuration example: # uid = nobody # gid = nobody # use chroot = yes # max connections = 4 # pid file = /var/run/rsyncd.pid # exclude = lost+found/ # transfer logging = yes # timeout = 900 # ignore nonreadable = yes # dont compress = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2 # [ftp] # path = /home/ftp # comment = ftp export area port=873 log file=/var/log/rsync/rsync.log pid file=/var/run/rsyncd.pid address=192.168.137.100 [test] path=/root/rsync use chroot=true max connections=4 ##最大连接数,默认为0,表示无限制 read only=no ##如果为true,则不能上传到该模块指定路径下 list=true ##用户是否可以查询该可用模块 uid=root ##传输时使用的UID gid=root auth users=test ##传输时使用的用户名 secrets file=/etc/rsyncd.passwd ##密码文件,不设置表示不使用。密码文件权限为600。 hosts allow=192.168.137.200 1.1.1.1 2.2.2.2 ##被允许连接该模块的主机 注:密码文件格式:用户名:密码 ②启动服务rsync --daemon 1 2 [root@juispan ~]#/usr/bin/rsync --daemon --config=/etc/rsyncd/rsyncd.conf ##config参数指定配置文件 如果需要关闭,可以kill进程。 ③客户端配置 Linux采用自带rsync,Windows采用cwRsync(client)端。 Linux系统中,可以手动执行,也可以执行脚本中的rsync。 ▽命令格式参考: 1 [root@server02 tmp]# rsync -av --progress rsync@192.168.137.100::backup ./test/ 本文转自Grodd51CTO博客,原文链接:http://blog.51cto.com/juispan/1949196,如需转载请自行联系原作者
1 2 3 4 5 6 7 8 9 10 转自:https://www.cnblogs.com/itech/archive/2012/05/15/2502284.html 一、inode是什么? 二、inode的内容 三、inode的大小 四、inode号码 五、目录文件 六、硬链接 七、软链接 八、inode的特殊作用 九、实际问题 一、inode是什么? 理解inode,要从文件储存说起。 文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector)。每个扇区储存512字节(相当于0.5KB)。 操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个"块"(block)。这种由多个扇区组成的"块",是文件存取的最小单位。"块"的大小,最常见的是4KB,即连续八个 sector组成一个 block。 文件数据都储存在"块"中,那么很显然,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode,中文译名为"索引节点"。二、inode的内容 inode包含文件的元信息,具体来说有以下内容: * 文件的字节数 * 文件拥有者的User ID * 文件的Group ID * 文件的读、写、执行权限 * 文件的时间戳,共有三个:ctime指inode上一次变动的时间,mtime指文件内容上一次变动的时间,atime指文件上一次打开的时间。 * 链接数,即有多少文件名指向这个inode * 文件数据block的位置 可以用stat命令,查看某个文件的inode信息: 1 2 3 4 5 6 7 8 9 [root@rc8f73133.cloud.nu17 /home/admin] #stat x.sh File: `x.sh' Size: 87 Blocks: 8 IO Block: 4096 regular file Device: 805h/2053d Inode: 9962245 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2017-11-09 10:10:35.758324514 +0800 Modify: 2017-05-23 11:04:14.265013018 +0800 Change: 2017-05-23 11:04:14.265013018 +0800 总之,除了文件名以外的所有文件信息,都存在inode之中。至于为什么没有文件名,下文会有详细解释。三、inode的大小 inode也会消耗硬盘空间,所以硬盘格式化的时候,操作系统自动将硬盘分成两个区域。 一个是数据区,存放文件数据; 另一个是inode区(inode table),存放inode所包含的信息。 每个inode节点的大小,一般是128字节或256字节。inode节点的总数,在格式化时就给定,一般是每1KB或每2KB就设置一个inode。 假定在一块1GB的硬盘中,每个inode节点的大小为128字节,每1KB就设置一个inode,那么inode table的大小就会达到128MB,占整块硬盘的12.8%。 查看每个硬盘分区的inode总数和已经使用的数量,可以使用df命令。 df -i 查看每个inode节点的大小,可以用如下命令: sudo dumpe2fs -h /dev/hda | grep "Inode size" 由于每个文件都必须有一个inode,因此有可能发生inode已经用光,但是硬盘还未存满的情况。这时,就无法在硬盘上创建新文件。四、inode号码 每个inode都有一个号码,操作系统用inode号码来识别不同的文件。 这里值得重复一遍,Unix/Linux系统内部不使用文件名,而使用inode号码来识别文件。 对于系统来说,文件名只是inode号码便于识别的别称或者绰号。表面上,用户通过文件名,打开文件。 实际上,系统内部这个过程分成三步: 首先,系统找到这个文件名对应的inode号码; 其次,通过inode号码,获取inode信息; 最后,根据inode信息,找到文件数据所在的block,读出数据。 使用ls -i命令,可以看到文件名对应的inode号码: ls -i example.txt 五、目录文件 Unix/Linux系统中,目录(directory)也是一种文件。打开目录,实际上就是打开目录文件。 目录文件的结构非常简单,就是一系列目录项(dirent)的列表。每个目录项,由两部分组成:所包含文件的文件名,以及该文件名对应的inode号码。 ls命令只列出目录文件中的所有文件名: ls /etc ls -i命令列出整个目录文件,即文件名和inode号码: ls -i /etc 如果要查看文件的详细信息,就必须根据inode号码,访问inode节点,读取信息。ls -l命令列出文件的详细信息。 ls -l /etc 六、硬链接 一般情况下,文件名和inode号码是"一一对应"关系,每个inode号码对应一个文件名。但是,Unix/Linux系统允许,多个文件名指向同一个inode号码。 这意味着,可以用不同的文件名访问同样的内容;对文件内容进行修改,会影响到所有文件名;但是,删除一个文件名,不影响另一个文件名的访问。这种情况就被称为"硬链接"(hard link)。 ln命令可以创建硬链接: ln 源文件 目标文件 运行上面这条命令以后,源文件与目标文件的inode号码相同,都指向同一个inode。 inode信息中有一项叫做"链接数",记录指向该inode的文件名总数,这时就会增加1。反过来,删除一个文件名,就会使得inode节点中的"链接数"减1。当这个值减到0,表明没有文件名指向这个inode,系统就会回收这个inode号码,以及其所对应block区域。 这里顺便说一下目录文件的"链接数"。创建目录时,默认会生成两个目录项:"."和".."。前者的inode号码就是当前目录的inode号码,等同于当前目录的"硬链接";后者的inode号码就是当前目录的父目录的inode号码,等同于父目录的"硬链接"。所以,任何一个目录的"硬链接"总数,总是等于2加上它的子目录总数(含隐藏目录),这里的2是父目录对其的“硬链接”和当前目录下的".硬链接“。 七、软链接 除了硬链接以外,还有一种特殊情况。文件A和文件B的inode号码虽然不一样,但是文件A的内容是文件B的路径。读取文件A时,系统会自动将访问者导向文件B。因此,无论打开哪一个文件,最终读取的都是文件B。这时,文件A就称为文件B的"软链接"(soft link)或者"符号链接(symbolic link)。 这意味着,文件A依赖于文件B而存在,如果删除了文件B,打开文件A就会报错:"No such file or directory"。这是软链接与硬链接最大的不同:文件A指向文件B的文件名,而不是文件B的inode号码,文件B的inode"链接数"不会因此发生变化。 ln -s命令可以创建软链接。 ln -s 源文文件或目录 目标文件或目录 八、inode的特殊作用 由于inode号码与文件名分离,这种机制导致了一些Unix/Linux系统特有的现象。 1. 有时,文件名包含特殊字符,无法正常删除。这时,直接删除inode节点,就能起到删除文件的作用。 2. 移动文件或重命名文件,只是改变文件名,不影响inode号码。 3. 打开一个文件以后,系统就以inode号码来识别这个文件,不再考虑文件名。因此,通常来说,系统无法从inode号码得知文件名。 第3点使得软件更新变得简单,可以在不关闭软件的情况下进行更新,不需要重启。因为系统通过inode号码,识别运行中的文件,不通过文件名。更新的时候,新版文件以同样的文件名,生成一个新的inode,不会影响到运行中的文件。等到下一次运行这个软件的时候,文件名就自动指向新版文件,旧版文件的inode则被回收。九、实际问题 在一台配置较低的Linux服务器(内存、硬盘比较小)的/data分区内创建文件时,系统提示磁盘空间不足,用df -h命令查看了一下磁盘使用情况,发现/data分区只使用了66%,还有12G的剩余空间,按理说不会出现这种问题。 后来用df -i查看了一下/data分区的索引节点(inode),发现已经用满(IUsed=100%),导致系统无法创建新目录和文件。 查找原因: /data/cache目录中存在数量非常多的小字节缓存文件,占用的Block不多,但是占用了大量的inode。 解决方案: 1、删除/data/cache目录中的部分文件,释放出/data分区的一部分inode。 2、用软连接将空闲分区/opt中的newcache目录连接到/data/cache,使用/opt分区的inode来缓解/data分区inode不足的问题: ln -s /opt/newcache /data/cache 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 df -i 和df -h 和stat命令详解 [root@rc8f73133.cloud.nu17 /home/admin] #df -h Filesystem Size Used Avail Use% Mounted on /dev/sda2 50G 38G 11G 22% / tmpfs 48G 11G 37G 24% /dev/shm /dev/sda1 253M 55M 186M 23% /boot /dev/sda5 1.1T 896G 167G 85% /home [root@rc8f73133.cloud.nu17 /home/admin] #df -i Filesystem Inodes IUsed IFree IUse% Mounted on /dev/sda2 3276800 153513 3123287 83% / tmpfs 12393777 17 12393760 1% /dev/shm /dev/sda1 65280 48 65232 1% /boot /dev/sda5 69697536 28417 69669119 1% /home 本文转自MT_IT51CTO博客,原文链接:http://blog.51cto.com/hmtk520/1983743,如需转载请自行联系原作者
shutil模块 shutil模块中包含一些函数,提供复制、移动、改名和删除文件的功能。要使用shutil的函数,首先需要import shutil。 调用shutil.copy(source,destination),将路径source处的文件复制到路径destination处的文件夹(source和destination都是字符串)。如果destination是一个文件名,它将作为被复制文件的新名字。该函数返回一个字符串,表示被复制文件的路径。 shutil.copy()将复制一个文件,shutil.copytree()将复制整个文件夹,以及它包含的文件夹和文件。shutil.copytree()函数返回一个字符串,是新复制的文件夹的路径。 1 2 3 4 5 6 7 8 9 10 >>> import shutil,os >>> os.chdir('/tmp/') >>> shutil.copy('./1.txt','/tmp/newdir/') '/tmp/newdir/1.txt' >>> shutil.copy('./1.txt','/tmp/newdir/2.txt') '/tmp/newdir/2.txt' >>> import os,shutil >>> shutil.copytree('/tmp/newdir','/usr/local/newdir_backup') '/usr/local/newdir_backup' 调用shutil.move(source,destination),将路径source处的文件夹移动到路径destination,并返回新位置的绝对路径的字符串。 如果找不到destination的文件夹,python会假定destination指的是一个文件,而非文件夹。 构成目的地的文件夹必须已经存在,否则python会抛出异常。 1 2 3 >>> import shutil >>> shutil.move('/usr/local/newdir_backup','/tmp/newdir/') '/tmp/newdir/newdir_backup' 利用os模块中的函数,可以删除一个文件或一个空文件夹。但利用shutil模块,可以删除一个文件夹及其所有的内容。 用os.unlink(path)将删除path处的文件。 调用os.rmdir(path)将删除path处的文件夹。该文件夹必须为空,其中没有任何文件和文件夹。 调用shutil.rmtree(path)将删除path处的文件夹,它包含的所有文件和文件夹都会被删除。 在程序中使用这些函数时,可以在第一次运行程序时,注释掉这些调用,并且加上print()调用,显示会被删除的文件。 1 2 3 4 5 import os for filename in os.listdir(): if filename.endswitch('.rxt'): #os.uplink(filename) print(filename) 使用内建的shutil.rmtree()函数不可恢复地删除文件和文件夹,所以用起来可能有危险。 删除文件和文件夹的更好方法,是使用第三方的send2trash模块。 它将文件夹和文件发送到计算机的垃圾箱或回收站,而不是永久删除它们。 一般来说,总是应该使用send2trash.send2trash()函数来删除文件和文件夹。 这种方式,不像永久删除文件,不会释放磁盘空间。 send2trash()函数只能将文件送到垃圾箱,不能从中恢复文件。 1 2 3 4 5 6 7 8 9 [root@juispan newdir]# pip install send2trash Collecting send2trash Downloading Send2Trash-1.3.0.tar.gz Building wheels for collected packages: send2trash Running setup.py bdist_wheel for send2trash ... done Stored in directory: /root/.cache/pip/wheels/15/76/b3/a81bb5d0bfc6157d1e5df52d34cbea6ffe8a0fc6fea83bddb0 Successfully built send2trash Installing collected packages: send2trash Successfully installed send2trash-1.3.0 1 2 3 4 5 >>> import send2trash >>> newFile=open('/tmp/new.txt','a') >>> newFile.write('Hello World!') >>> newFile.close() >>> send2trash.send2trash('/tmp/new.txt') 遍历目录树 os.walk()函数被传入一个字符串值,即一个文件夹的路径。 可以在一个for循环语句中使用os.walk()函数,遍历目录树,就像使用range()函数遍历一个范围的数字一样。 ▎不像range(),os.walk()在循环的每次迭代中,返回3个值: 1、当前文件夹名称的字符串。 2、当前文件夹中子文件夹的字符串的列表。 3、当前文件夹中文件的字符串的列表。 所谓的当前文件夹,是指for循环当前迭代的文件夹。程序的当前工作目录,不会因为os.walk()而改变。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 >>> import os >>> for dir,subdirs,files in os.walk('/tmp/'): ... print('dir: '+dir) ... for subdir in subdirs: ... print('subdir: '+subdir) ... for file in files: ... print('file: '+file) ... print('') ... dir: /tmp/ subdir: .font-unix subdir: .X11-unix subdir: .ICE-unix subdir: .Test-unix ...... zipfile模块 将多个文件打包成一个文件,这个文件叫做“归档文件”。 要创建一个ZipFile对象,就调用zipfile.ZipFile()函数,向它传入一个字符串,表示.zip文件的文件名。 zipfile是python模块的名称,ZipFile()是函数的名称。 ZipFile对象有一个namelist()方法,返回ZIP文件中包含的所有文件和文件夹的字符串的列表。这些字符串可以传递给ZipFile对象的getinfo()方法,返回一个关于特定文件的ZipInfo对象。ZipInfo对象有自己的属性,诸如表示字节数的file_size和compress_size,它们分别表示原来文件大小和压缩后文件大小。ZipFile对象表示整个归档文件,而ZipInfo对象则保存该归档文件中每个文件的有用信息。 1 2 3 4 5 6 7 8 9 10 >>> import zipfile,os >>> zipFile=zipfile.ZipFile('/tmp/new.zip') >>> zipFile.namelist() ['tmp/newdir/1.txt'] >>> zipInfo=zipFile.getinfo('tmp/newdir/1.txt') >>> zipInfo.file_size 1100 >>> zipInfo.compress_size 482 >>> zipFile.close() ZipFile对象的extractall()方法从ZIP文件中解压缩所有文件和文件夹,放到当前工作目录中。 如果传递给extractall()方法的文件夹不存在,它会被创建。 extract()方法可以从ZIP文件中解压缩单个文件。 传递给extract()的字符串,必须匹配namelist()返回的字符串列表中的一个。 可以向extract()传递第二个参数,将文件解压缩到指定的文件夹,而不是当前工作目录。 如果第二个参数指定的文件夹不存在,python就会创建它。 extract()的返回值是被压缩后文件的绝对路径。 1 2 3 4 >>> import os,zipfile >>> extractZip=zipfile.ZipFile('/tmp/new.zip') >>> extractZip.extractall() >>> extractZip.close() 如果向ZipFile对象的write()方法传入一个路径,python就会压缩该路径所指的文件,将它加入ZIP文件中。 write()方法的第一个参数是一个字符串,代表要添加的文件名。第二个参数是“压缩类型”参数,可以总是设置为“zipfile.ZIP_DEFLATED”。 就像写入文件一样,写模式将擦除ZIP文件中所有原有的内容。如果需要添加,使用“a”作为第二个参数。 1 2 3 4 >>> import zipfile,os >>> newZip=zipfile.ZipFile('/tmp/new.zip','w') >>> newZip.write('/tmp/newdir/1.txt',compress_type=zipfile.ZIP_DEFLATED) >>> newZip.close() 本文转自Grodd51CTO博客,原文链接:http://blog.51cto.com/juispan/1950074,如需转载请自行联系原作者
要点亮LED灯或获得输入IO的状态应该是比较容易的,打开端口时钟,然后读写相关的GPIO寄存器就可以了,但是要实现一个输入中断,就要费些周折了。 对STM32(Cortex-M3)的芯片,要实现一个GPIO中断一般需要如下几步: 1、 配置时钟控制器寄存器(RCC)的APB2RSTR,确保对应的GPIOA ~ GPIOG时钟使能。 2、 对GPIO寄存器的CRL(或CRH)要设置正确的输入模式,如浮空输入模式(对接收IO中断来说,当然要设置成输入模式)。 3、 要通过AFIO寄存器配置中断的输入来源,对STM32芯片来说,具有19路EXTI中断线,其中3路分别连接PVD输出、RTC闹钟事件及USB唤醒事件,剩下的对GPIOA ~ GPIOG 7*16=112个IO点来说,同时只能配置16路IO输入中断。 4、 接下来要配置EXIT寄存器,根据需要来配置是上升沿触发中断、还是下降沿触发中断或两者都触发。 5、 而后比较重要的是, 要配置NVIC的SETENA寄存器,让对应的EXTI0、EXTI1、EXTI2、EXTI3、EXTI4、EXTI9_5或EXTI15_10中断位使能,此外还要配置各中断的优先级(前提是中断优先级分组寄存器已配置完毕)。 6、 最后我们要设置中断向量表(该向量表要重定位到内存中,以便于动态修改),在EXTI0、EXTI1、EXTI2、EXTI3、EXTI4、EXTI9_5或EXTI15_10对应的位置,放入我们的中断函数的入口地址。 和PC平台程序开发不同,基本上你每做一步,都可以很直观的看到你的进展和成果,但对嵌入式开发来说,如果上述几步有任何一个环节出了问题,你的进展都是零,有时候你会花上一天的时间去反复核实每个寄存器的值是否正确,以期获得你希望的结果。所以说嵌入式开发是惊喜的型的,要么成,要么不成,一线之隔! 接下来我们说一下GPIO实现的详细步骤,首先在CortexM3.h头文件中添加GPIO相关的寄存器描述: struct CortexM3_GPIO { static const UINT32 c_Base = 0x40010800; static const UINT32 A = 0; static const UINT32 B = 1; static const UINT32 C = 2; static const UINT32 D = 3; static const UINT32 E = 4; static const UINT32 F = 5; static const UINT32 G = 6; static const UINT32 GPIO_Mode_NULL = 0x00; static const UINT32 GPIO_Mode_Speed_10MHz = 0x01; static const UINT32 GPIO_Mode_Speed_2MHz = 0x02; static const UINT32 GPIO_Mode_Speed_50MHz = 0x03; static const UINT32 GPIO_Mode_IN_FLOATING = 0x04; /****/ volatile UINT32 CRL; //配置寄存器 /****/ volatile UINT32 CRH; /****/ volatile UINT32 IDR; //数据寄存器 /****/ volatile UINT32 ODR; /****/ volatile UINT32 BSRR; //置位复位寄存器 /****/ volatile UINT32 BRR; //复位寄存器 /****/ volatile UINT32 LCKR; //锁定寄存器 }; struct CortexM3_EXTI { static const UINT32 c_Base = 0x40010400; /****/ volatile UINT32 IMR; /****/ volatile UINT32 EMR; /****/ volatile UINT32 RTSR; /****/ volatile UINT32 FTSR; /****/ volatile UINT32 SWIER; /****/ volatile UINT32 PR; }; struct CortexM3_AFIO { static const UINT32 c_Base = 0x40010000; /****/ volatile UINT32 EVCR; /****/ volatile UINT32 MAPR; /****/ volatile UINT32 EXTICR[4]; }; 由于NVIC相关的代码我们已经在《NVIC中断处理》说过了,这里就不重复了。 对.Net Micro Framework的架构来说,要实现如下几个接口: 1、CPU_GPIO_Initialize 2、CPU_GPIO_Uninitialize 3、CPU_GPIO_Attributes 4、CPU_GPIO_DisablePin 5、CPU_GPIO_EnableOutputPin 6、CPU_GPIO_EnableInputPin 7、CPU_GPIO_EnableInputPin2 8、CPU_GPIO_GetPinState 9、CPU_GPIO_SetPinState 10、CPU_GPIO_GetPinCount 11、CPU_GPIO_GetPinsMap 12、CPU_GPIO_GetSupportedResistorModes 13、CPU_GPIO_GetSupportedInterruptModes 14、CPU_GPIO_PinIsBusy 15、CPU_GPIO_ReservePin 16、CPU_GPIO_GetDebounce 17、CPU_GPIO_SetDebounce 考虑到难易程度和篇幅,我们只介绍CPU_GPIO_Initialize、CPU_GPIO_EnableOutputPin、 CPU_GPIO_EnableInputPin和EXTI_IRQHandler 中断函数的具体实现。 BOOL GPIO_Driver::Initialize() { CortexM3_AFIO &AFIO = CortexM3::AFIO(); for(int i=0;i<4;i++) { AFIO.EXTICR[i]=0x0000; } CortexM3_EXTI &EXTI= CortexM3::EXTI(); EXTI.IMR = 0x00000000; EXTI.EMR = 0x00000000; EXTI.RTSR = 0x00000000; EXTI.FTSR = 0x00000000; EXTI.PR = 0x0007FFFF; //NVIC if(!CPU_INTC_ActivateInterruptEx(CortexM3_NVIC::c_IRQ_Index_EXTI0,(UINT32)(void *)EXTI_IRQHandler )) return FALSE; //略 return TRUE; } 其中比较重要的是CPU_INTC_ActivateInterruptEx函数,它可动态设置c_IRQ_Index_EXTI0中断所对应的中断函数的入口地址。 void GPIO_Driver::EnableOutputPin(GPIO_PIN pin, BOOL initialState) { ASSERT(pin < c_MaxPins); UINT32 port = PinToPort(pin); UINT32 bit = PinToBit(pin); UINT32 pos = (bit % 8)<<2; CortexM3_GPIO &GPIO= CortexM3::GPIO(port); //通用推挽输出模式 if(bit<8) { GPIO.CRL = (GPIO.CRL & ~(0x0F << pos)) | (CortexM3_GPIO::GPIO_Mode_Speed_50MHz << pos); } else { GPIO.CRH = (GPIO.CRH & ~(0x0F << pos)) | (CortexM3_GPIO::GPIO_Mode_Speed_50MHz << pos); } //初值 if(initialState) GPIO.BSRR = 0x1 << bit; else GPIO.BRR = 0x1 << bit; } 输出默认为通用推挽输出模式,你也可以根据实际需要进行必要的调整。 BOOL GPIO_Driver::EnableInputPin(GPIO_PIN pin, BOOL GlitchFilterEnable, GPIO_INTERRUPT_SERVICE_ROUTINE ISR, void *pinIsrParam, GPIO_INT_EDGE intEdge, GPIO_RESISTOR resistorState) { ASSERT(pin < c_MaxPins); UINT32 port = PinToPort(pin); UINT32 bit = PinToBit(pin); UINT32 pos = (bit % 8)<<2; CortexM3_GPIO &GPIO= CortexM3::GPIO(port); //浮空输入 if(bit<8) { GPIO.CRL = (GPIO.CRL & ~(0x0F << pos))| (CortexM3_GPIO::GPIO_Mode_IN_FLOATING << pos); } else { GPIO.CRH = (GPIO.CRH & ~(0x0F << pos))| (CortexM3_GPIO::GPIO_Mode_IN_FLOATING << pos); } //中断输入源配置(AFIO) CortexM3_AFIO &AFIO = CortexM3::AFIO(); AFIO.EXTICR[bit >> 2] &= ~(0x0F << (0x04 * (bit & 0x03))); AFIO.EXTICR[bit >> 2] |= port << (0x04 * (bit & 0x03)); CortexM3_EXTI &EXTI=CortexM3::EXTI(); if(ISR) { switch(intEdge) { case GPIO_INT_NONE: //无中断 EXTI.IMR &= ~(0x1<<bit); return FALSE; case GPIO_INT_EDGE_LOW: //下降沿中断 case GPIO_INT_LEVEL_LOW: EXTI.IMR |= 0x1<<bit; EXTI.FTSR |= 0x1<<bit; //下降沿有效 EXTI.RTSR &= ~(0x1<<bit); //上升沿无效 break; //略 default: ASSERT(0); return FALSE; } } return TRUE; } GPIO输入的实现比较繁琐一些,可以根据需要仅把端口配置成输入模式,而不配置相应的中断参数。这样可以通过不断扫描的方式获得输入信号。 void GPIO_Driver::ISR(void *Param) { CortexM3_EXTI &EXTI=CortexM3::EXTI(); UINT32 interruptsActive = EXTI.PR; UINT32 bitMask = 0x1, bitIndex = 0; while(interruptsActive) { while((interruptsActive & bitMask) == 0) { bitMask <<= 1; ++bitIndex; } CortexM3_AFIO &AFIO = CortexM3::AFIO(); UINT32 port = (AFIO.EXTICR[bitIndex >> 2]>>(0x04 * (bitIndex & 0x03))) & 0xF; GPIO_PIN pin = BitToPin( bitIndex, port); PIN_ISR_DESCRIPTOR& pinIsr = g_GPIO_Driver.m_PinIsr[ pin ]; pinIsr.Fire( (void*)&pinIsr ); interruptsActive ^= bitMask; EXTI.PR |= bitMask; } } 在中断函数中,根据相关寄存器的值来判断哪一个(或同时哪一些)GPIO发生的中断,并由此执行业已配置好的异步中断处理函数。 好了,写完了GPIO驱动程序,我们就可以漂漂亮亮的在NativeSample中写我们的测试程序了: void ISR( GPIO_PIN Pin, BOOL PinState, void* Param ) { if(PinState) // released, up { CPU_GPIO_SetPinState(GPIO_Driver::PF7,0x0); } else // pressed, down { CPU_GPIO_SetPinState(GPIO_Driver::PF7,0x1); } } void ApplicationEntryPoint() { //LED D1 D2 D3 D4 CPU_GPIO_EnableOutputPin(GPIO_Driver::PF7,FALSE); CPU_GPIO_EnableOutputPin(GPIO_Driver::PF8,FALSE); //user按钮 = 0x1 CPU_GPIO_EnableInputPin(GPIO_Driver::PG8,FALSE,ISR,GPIO_INT_EDGE_BOTH,RESISTOR_PULLDOWN); while(TRUE) { CPU_GPIO_SetPinState(GPIO_Driver::PF8,!CPU_GPIO_GetPinState(GPIO_Driver::PF8)); Events_WaitForEvents( 0, 1000 ); } } 上面的程序比我们最初在《调试初步:点亮LED灯》中提到的代码清爽多了,把程序下载到开发板上运行,你会发现D3 LED灯以一秒为周期不断地闪烁,而D2 LED灯则在user按钮按下时才亮,放开时则灭。 只要细心 + 耐心,其实嵌入式开发还是比较容易的,并且功能实现那一刻喜悦的“强度”,是作为PC平台软件开发者所难以企及的 本文转自yefanqiu51CTO博客,原文链接:http://blog.51cto.com/yfsoft/321228,如需转载请自行联系原作者
1、请按照这样的日期格式(xxxx-xx-xx)每日生成一个文件,例如今天生成的文件为2017-07-05.log, 并且把磁盘的使用情况写到到这个文件中,(不用考虑cron,仅仅写脚本即可)! 1 2 3 4 #! /bin/bash d=`date +%F` logfile=$d.log df -h > $logfile 2、统计日志 有日志1.log,内容如下: 日志片段: 1 2 112.111.12.248 - [25/Sep/2013:16:08:31 +0800]formula-x.haotui.com "/seccode.php?update=0.5593110133088248" 200"http://formula-x.haotui.com/registerbbs.php" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;)" 61.147.76.51 - [25/Sep/2013:16:08:31 +0800]xyzdiy.5d6d.com "/attachment.php?aid=4554&k=9ce51e2c376bc861603c7689d97c04a1&t=1334564048&fid=9&sid=zgohwYoLZq2qPW233ZIRsJiUeu22XqE8f49jY9mouRSoE71" 301"http://xyzdiy.***thread-1435-1-23.html" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" 要求: 统计出每个IP的访问量有多少? 1 # awk '{print $1}' 1.log |sort -n|uniq -c 3、统计内存使用 写一个脚本计算一下linux系统所有进程占用内存大小的和。(提示,使用ps或者top命令) 1 2 3 4 5 6 7 #! /bin/bash sum=0 for mem in `ps aux |awk '{print $6}' |grep -v 'RSS' ` do sum=$[$sum+$mem] done echo "The total memory is $sum""k" 也可以使用awk 一条命令计算: 1 #ps aux | grep -v 'RSS TTY' |awk '{(sum=sum+$6)};END{print sum}' 4、设计监控脚本 监控远程的一台机器(假设ip为123.23.11.21)的存活状态,当发现宕机时发一封邮件给你自己。 提示: 你可以使用ping命令 ping -c10 123.23.11.21 发邮件脚本可以参考 https://coding.net/u/aminglinux/p/aminglinux-book/git/blob/master/D22Z/mail.py 脚本可以搞成死循环,每隔30s检测一次 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #!/bin/bash ip=123.23.11.21 ma=abc@139.com while 1 do ping -c10 $ip >/dev/null 2>/dev/null if [ $? != "0" ] then python /usr/local/sbin/mail.py $ma "$ip down" "$ip is down,plese check." #假设mail.py已经编写并设置好了 fi sleep 30 done 5、批量更改文件名 找到/123目录下所有后缀名为.txt的文件 批量修改.txt为.txt.bak 把所有.bak文件打包压缩为123.tar.gz 批量还原文件的名字,即把增加的.bak再删除 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #!/bin/bash ##查找txt文件 find /123 -type f -name "*.txt" > /tmp/txt.list ##批量修改文件名 for f in `cat /tmp/txt.list` do mv $f $f.bak done ##创建一个目录,为了避免目录已经存在,所以要加一个复杂的后缀名 d=`date +%y%m%d%H%M%S` mkdir /tmp/123_$d ##把.bak文件拷贝到/tmp/123_$d for f in `cat /tmp/txt.list` do cp $f.bak /tmp/123_$d done ##打包压缩 cd /tmp/ tar czf 123.tar.gz 123_$d/ ##还原 for f in `cat /tmp/txt.list` do mv $f.bak $f done 本文转自Grodd51CTO博客,原文链接:http://blog.51cto.com/juispan/1951336,如需转载请自行联系原作者
准备工作 1 2 3 4 5 6 7 8 9 10 11 cd /usr/local/src wget http://mirrors.sohu.com/mysql/MySQL-5.6/mysql-5.6.35-linux-glibc2.5-x86_64.tar.gz wget http://mirrors.cnnic.cn/apache/httpd/httpd-2.4.27.tar.gz wget http://mirrors.hust.edu.cn/apache/apr/apr-1.5.2.tar.gz wget http://mirrors.hust.edu.cn/apache/apr/apr-util-1.5.4.tar.gz wget http://cn2.php.net/distributions/php-5.6.30.tar.gz tar zxf mysql-5.6.35-linux-glibc2.5-x86_64.tar.gz tar zxf apr-1.5.2.tar.gz tar zxf apr-util-1.5.4.tar.gz tar zxf httpd-2.4.27.tar.gz tar zxf php-5.6.30.tar.gz 软件安装 MySQL 1 2 3 4 5 6 7 8 9 10 11 12 13 mv mysql-5.6.35-linux-glibc2.5-x86_64 /usr/local/mysql cd ../mysql/ useradd mysql mkdir /data/ yum install -y perl perl-Data-Dumper libaio libaio-devel ./scripts/mysql_install_db --user=mysql --datadir=/data/mysql cp support-files/my-default.cnf /etc/my.cnf cp support-files/mysql.server /etc/init.d/mysqld vi /etc/init.d/mysqld basedir=/usr/local/mysql datadir=/data/mysql chkconfig --add mysqld service mysqld start Apache 1 2 3 4 5 6 7 8 9 10 11 12 13 wget http://vault.centos.org/5.7/os/x86_64/CentOS/kernel-headers-2.6.18-274.el5.x86_64.rpm rpm -ivh kernel-headers-2.6.18-274.el5.x86_64.rpm yum install -y gcc pcre-devel cd /usr/local/src/apr-1.5.2 ./configure --prefix=/usr/local/apr make && make install cd /usr/local/src/apr-util-1.5.4 ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr make && make install cd /usr/local/src/httpd-2.4.27 ./configure --prefix=/usr/local/apache2.4 --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr-util --enable-so --enable-mods-shared=most make && make install /usr/local/apache2.4/bin/httpd -k start PHP 1 2 3 4 5 yum install -y libxml2-devel openssl-devel bzip2-devel libjpeg-turbo-devel libpng-devel freetype-devel libmcrypt-devel cd /usr/local/src/php-5.6.30 ./configure --prefix=/usr/local/php --with-apxs2=/usr/local/apache2.4/bin/apxs --with-config-file-path=/usr/local/php/etc --with-mysql=/usr/local/mysql --with-pdo-mysql=/usr/local/mysql --with-mysqli=/usr/local/mysql/bin/mysql_config --with-libxml-dir --with-gd --with-jpeg-dir --with-png-dir --with-freetype-dir --with-iconv-dir --with-zlib-dir --with-bz2 --with-openssl --with-mcrypt --enable-soap --enable-gd-native-ttf --enable-mbstring --enable-sockets --enable-exif make &&make install cp php.ini-production /usr/local/php/etc/php.ini 配置LAMP 1 2 3 4 5 6 7 8 9 10 11 vi /usr/local/apache2.4/conf/httpd.conf ServerName www.example.com:80 <Directory /> AllowOverride none Require all granted </Directory> <IfModule dir_module> DirectoryIndex index.html index.php </IfModule> AddType application/x-httpd-php .php iptables -I INPUT -p tcp --dport 80 -j ACCEPT 配置华为云主机 效果测试 1 2 3 4 5 vi /usr/local/apache2.4/htdocs/index.php <?php phpinfo(); ?> /usr/local/apache2.4/bin/apachectl graceful 本文转自Grodd51CTO博客,原文链接:http://blog.51cto.com/juispan/1953771,如需转载请自行联系原作者
PersonDAOProxyJDBC.java package org.michael.demo.proxy; import java.util.Set; import org.michael.demo.dao.PersonDAO; import org.michael.demo.dao.impl.PersonDAOImplJDBC; import org.michael.demo.vo.Person; public class PersonDAOProxyJDBC implements PersonDAO { private PersonDAO dao = null; public PersonDAOProxyJDBC(String type) { this.dao = new PersonDAOImplJDBC(type); } public boolean doCreate(Person person) throws Exception { // TODO Auto-generated method stub return this.dao.doCreate(person); } public boolean doDelete(String id) throws Exception { // TODO Auto-generated method stub return this.dao.doDelete(id); } public boolean doUpdate(Person person) throws Exception { // TODO Auto-generated method stub return this.dao.doUpdate(person); } public Set<Person> findAll() throws Exception { // TODO Auto-generated method stub return this.dao.findAll(); } public Person findById(String id) throws Exception { // TODO Auto-generated method stub return this.dao.findById(id); } public Set<Person> findByLike(String keyWord) throws Exception { // TODO Auto-generated method stub return this.dao.findByLike(keyWord); } } InputData.java package org.michael.demo.util; //输入数据的操作类 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class InputData { private BufferedReader buf = null; public InputData() { buf = new BufferedReader(new InputStreamReader(System.in)); } public int getInt() { int temp = 0; // 如果输入的不是数字,至少应该有一个提示,告诉用户输入错了 // 可以使用正则验证 String str = null; boolean flag = true; while (flag) { // 输入数据 str = this.getString(); if (!(str.matches("\\d+"))) { // 如果不是一个数字,则必须重新输入 System.out.print("输入的内容,必须是整数,请重新输入:"); } else { // 是一个正确的数字,则可以进行转换 temp = Integer.parseInt(str); // 表示退出循环 flag = false; } } return temp; } public String getString() { String str = null; try { str = buf.readLine(); } catch (IOException e) { e.printStackTrace(); } return str; } public float getFloat() { float f = 0.0f; String str = null; boolean flag = true; while (flag) { // 输入数据 str = this.getString(); if (!(str.matches("\\d+.?\\d{1,2}"))) { // 如果不是一个数字,则必须重新输入 System.out.print("输入的内容,必须是小数(小数点后只到两位),请重新输入:"); } else { // 是一个正确的数字,则可以进行转换 f = Float.parseFloat(str); // 表示退出循环 flag = false; } } return f; } } TimeStamp.java package org.michael.demo.util; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.Random; // 取得时间戳的类 public class TimeStamp { private Calendar calendar = null; // 此标记有外部决定 private String flag = null; public TimeStamp() { this.calendar = new GregorianCalendar(); } public TimeStamp(String flag) { this() ; this.flag = flag; } public String getTimeStamp() { StringBuffer buf = new StringBuffer(); if (this.flag != null) { buf.append(this.flag); } buf.append(this.addZero(calendar.get(Calendar.YEAR), 4)); buf.append(this.addZero(calendar.get(Calendar.MONTH) + 1, 2)); buf.append(this.addZero(calendar.get(Calendar.DAY_OF_MONTH), 2)); buf.append(this.addZero(calendar.get(Calendar.HOUR_OF_DAY), 2)); buf.append(this.addZero(calendar.get(Calendar.MINUTE), 2)); buf.append(this.addZero(calendar.get(Calendar.SECOND), 2)); buf.append(this.addZero(calendar.get(Calendar.MILLISECOND), 3)); return buf.toString(); } public String getTimeStampRandom() { StringBuffer buf = new StringBuffer(); Random r = new Random(); buf.append(this.getTimeStamp()); buf.append(r.nextInt(10)); buf.append(r.nextInt(10)); buf.append(r.nextInt(10)); return buf.toString(); } // 可以单独设置一个加“0”的操作 private String addZero(int temp, int len) { String str = temp + ""; while (str.length() < len) { str = "0" + str; } return str; } } Person.java package org.michael.demo.vo; import java.io.Serializable; public abstract class Person implements Comparable<Object>,Serializable { // 定义各公共属性 private String id ; private String name ; private int age ; public Person(String id,String name,int age){ this.setId(id) ; this.setName(name) ; this.setAge(age) ; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } Student.java package org.michael.demo.vo; public class Student extends Person { private static final long serialVersionUID = 1L; private float score; public Student(String id, String name, int age, float score) { super(id, name, age); this.setScore(score); } public int compareTo(Object arg0) { Student s = (Student) arg0; if (this.score < s.score) { return 1; } else if (this.score > s.score) { return -1; } else { if (super.getAge() < s.getAge()) { return -1; } else if (super.getAge() > s.getAge()) { return 1; } else { return 0; } } } public String toString() { return this.getId() + "\t" + this.getName() + "\t" + this.getAge() + "\t" + this.score; } public float getScore() { return score; } public void setScore(float score) { this.score = score; } } Worker.java package org.michael.demo.vo; public class Worker extends Person { private static final long serialVersionUID = 1L; private float salary; public Worker(String id, String name, int age, float salary) { super(id, name, age); this.setSalary(salary); } public int compareTo(Object arg0) { Worker w = (Worker) arg0; if (this.salary < w.salary) { return 1; } else if (this.salary > w.salary) { return -1; } else { if (super.getAge() < w.getAge()) { return -1; } else if (super.getAge() > w.getAge()) { return 1; } else { return 0; } } } public String toString() { return this.getId() + "\t" + this.getName() + "\t" + this.getAge() + "\t" + this.salary; } public float getSalary() { return salary; } public void setSalary(float salary) { this.salary = salary; } } 测试: ####################Michael分割线########################### 本身显示的效果并不复杂,但是在此程序中重点是体现了一种程序的设计的分层思路,如果可以做的再好,最好把学生和工人的操作分开,分别完成。 建立一个专门的:StudentDAO操作 建立一个专门的:WorkerDAO操作 这样的话通过工厂分别取得两个接口的实例,就可以避免传递参数了。 所有的类要分别按不同的包存放,而且在写代码的时候必须使用考虑如果万一修改了该怎么办? ####################Michael分割线########################### 源代码下载 #################Michael分割线#################### 本文转自redking51CTO博客,原文链接:http://blog.51cto.com/redking/145389,如需转载请自行联系原作者
本文转自Grodd51CTO博客,原文链接:http://blog.51cto.com/juispan/1953916,如需转载请自行联系原作者
从2002年就开始接触Modbus协议,以后陆续在PLC、DOS、Windows、.Net Micro Framework等系统中使用了该协议,在我以前写的一篇博文中详细记载了这一段经历,有兴趣的朋友可以看一看《我的Modbus Slave/Client开发历程(Rtu/AscII/Tcp)》。该协议公开,精简,并且可靠,目前大部分智能仪表,智能模块和一些PLC都采用了该协议,前一段时间有位网友询问相关Modbus的问题,所以这里就以Modbus的实现来来作为.Net MF开发板的串口示例。 本示例包含两部分,一部分运行到开发板上,作为Modbus RTU Slave服务存在;另一部分典型的.Net Framework代码,实现了Modbus RTU Client端功能,可以借助开发板上的Slave服务控制开发板上的LED灯和获取按钮状态。 Slave类的实现如下(具体实现请参见示例源码): namespace YFSoft.Modbus { public class Slave { //数据区读写事件 public event ReadDataEventHandler ReadData; public event WriteDataEventHandler WriteData; //启动Modbus服务 public void Start(string portName, int baudRate, Parity parity); //停止Modbus服务 public void Stop(); } } 调用相对简单,代码如下: public static void Main() { Graphics.Clear(Color.Black); Graphics.Print("Modbus Rtu Test\r\n"); … … RtuSlave.ReadData += new ReadDataEventHandler(RtuSlave_ReadData); RtuSlave.WriteData += new WriteDataEventHandler(RtuSlave_WriteData); RtuSlave.Start("COM2", 19200, System.IO.Ports.Parity.None); int index = 0; while (true) { //leds[0].Write(!leds[0].Read()); Graphics.FillRectangle(0, 305, 240, 15, Color.White); Graphics.DrawString(5, 306, (index++).ToString(), Color.Blue); Thread.Sleep(1000); } //RtuSlave.Stop(); } 比较重要的是下面的代码,它们具体实现读写LED的状态及按钮状态,需要注意的是红牛的开发板和EM-STM3210E的LED有些不同,一个是输出电平为低时点亮,一个是输出电平为高时点亮,相关代码如下: static void RtuSlave_WriteData(int addr, int size, ref byte[] data) { //写LED if (addr == 0) { for (int i = 0; i < leds.Length; i++) { #if Redox leds[i].Write(!((data[1] & 0x1<<i) > 0)); #else leds[i].Write((data[1] & 0x1 << i) > 0); #endif } } } static void RtuSlave_ReadData(int addr, int size, ref byte[] data) { if (addr < 2) { //读LED byte bytTemp = 0; for (int i = 0; i < leds.Length; i++) { #if Redox bytTemp |= (byte)((leds[i].Read() ? 0 : 1) << i); #else bytTemp |= (byte)((leds[i].Read() ? 1 : 0) << i); #endif } data[1] = bytTemp; //读Button bytTemp = 0; for (int i = 0; i < buttons.Length; i++) { bytTemp |= (byte)((buttons[i].Read() ? 1 : 0) << i); } data[3] = bytTemp; } } PC机上的.Net Framework代码实现了一个Modbus Rtu Client类,相关接口如下: namespace YFSoft.Modbus { public class Client { public bool Open(string portName, int baudRate, Parity parity); public int Read(byte Addr, UInt16 DataAddr, UInt16[] DataValue, UInt16 DataNum); public int Write(byte Addr, UInt16 DataAddr, UInt16[] DataValue, UInt16 DataNum); } } 由于.Net Framework代码不是介绍的重点,感兴趣的朋友直接看相关源码(其实该套源码几乎不需要修改,就可以直接成为.Net Micro Framewor的代码,这也正是.Net Micro Framework的魅力之所在)。 下位机机运行后的效果图如下: 注意:红牛代码和EM-STM3210E不同,后者需要注释掉 #define Redox 代码。 上位机代码解压后,直接运行即可,程序的相关参数已经配好,如果启动时,开发板已经正常运行,并且和PC进行了串口连接,则会显示如下画面。按开发板上的按钮,这是按钮状态会有变化,用鼠标单击LED区的鼠标,你会发现开发板上的LED灯会做同步改变。 这应该是关于Modbus示例代码中的重量级示例,因为Client和Slave的源码都涉及到了,并且相关代码不仅仅是示例,也来源于我以前所做的工程项目,所以非常有价值。 下一篇文章将介绍和所做的,就是我们就要把Modbus Client端移植到开发板上运行了,对红牛开发板来说,我们通过COM3的485接口直接控制PLC,不过对EM-STM3210E开发板来说,没有这么爽,它不光没有485接口,并且COM3口也没有引出了,所以要想访问PLC,一般需要中间接一个232转485设备,不管怎样,我们的开发板不仅上可以给PC通信,下也可以和PLC通信了。 ----------------------------------------------------------------------------------------- 【低价开发板】http://item.taobao.com/item.htm?id=7117999726 源码下载:http://www.sky-walker.com.cn/yefan/MFV40/SourceCode/Modbus.rar 文章参考: 《.Net Micro Framework 快速入门》 中文讨论组:http://space.cnblogs.com/group/MFSoft/ 本文转自yefanqiu51CTO博客,原文链接:http://blog.51cto.com/yfsoft/343819,如需转载请自行联系原作者
上篇文章我们用手机上的蓝牙去控制智能小车,这次我们直接用笔记本上的蓝牙模块来控制小车,这样利用PC更为强大的运算能力,就可以扩展出更多有意思的功能来。 下面就是PC蓝牙模块的设置步骤(注意,需保证与小车相连的蓝牙模块上电) 1、 在控制面板中双击蓝牙图标 2、 蓝牙设备属性面板 3、 添加蓝牙设备 4、 找到蓝牙设备 5、 设置密钥 6、 设备安装 7、 安装成功 配置完成后,蓝牙通信就完全就变成了串口通信,所以相关的代码我这里就不重复介绍了,需要提醒的是,蓝牙模块要求的通信波特率为57600,且PC的通信串口为COM5,具体代码请参见《Zigbee遥控智能小车》和《蓝牙遥控智能小车(手机模式)》。 public frmMain() { InitializeComponent(); serial = new SerialPort("COM5", 57600, Parity.None, 8, StopBits.One); serial.Open(); } 运行后的界面如下: 单击相关按钮,如果不出意外的话,在蓝牙通信范围的智能小车应该已经动起来了。 相关控制视频如下(和PC控制Zigbee的模式一致): http://video.sina.com.cn/v/b/40292033-1804832611.html (1)、小车底盘 http://item.taobao.com/item.htm?id=7218838776 (2)、四路直流电机驱动器 http://item.taobao.com/item.htm?id=7218717808 (3)、.NET Micro Framework开发板 http://item.taobao.com/item.htm?id=7117999726 (4)、蓝牙模块 http://item.taobao.com/auction/item_detail.htm?item_num_id=8333868680 注:需要红牛开发板固件在 V1.0.0以上 注:此蓝牙模块的通信波特率为9600,默认配对密码 1234,采用这款模块,记得把相关波特率由57600修改为9600。 本文源码:http://www.sky-walker.com.cn/yefan/MFV40/SourceCode/BluetoothCar.rar 本文源码:http://www.sky-walker.com.cn/yefan/MFV40/SourceCode/PCBluetooth.rar MF快速参考: .NET Micro Framework 快速入门 MF中文讨论组:http://space.cnblogs.com/group/MFSoft/ 微软官方论坛:MSDN微软中文技术论坛(.NET Micro Framework) 开发板简明手册:http://blog.sina.com.cn/s/blog_6b938f630100kh0k.html 【低价开发板】http://item.taobao.com/item.htm?id=7117999726 本文转自yefanqiu51CTO博客,原文链接:http://blog.51cto.com/yfsoft/425157,如需转载请自行联系原作者
Microsoft Windows Mobile 设备中心 6.1 在6月6日发布了最新版,今天为了能在Vista开发PPC(或Wince设备)程序,下载安装了该程序,启动后界面确实很炫,和媒体中心的风格有些类似。不过我用VS2005开发的程序,通过该程序还是无法和我的PPC通信,不知道是否是没有安装mobile 5.0 SDK的原因?不管怎样在Vista平台上,已经通过它可以访问我的PPC上的文件了。 图1:初始界面就感觉很炫 图2:连接配置和ActiveSync没有什么区别 图3:已建立连接 图4:这是控制面板中的同步中心 图5:连接后的设备中心主界面 图6:这是PPC上的文件目录,注意看和ActiveSync有了区别 图7:这是PPC内存的文件,注意看windows文件夹不见了! 图8:用VS2005联调设备还是不行。 Mobile 设备中心 6.1 的下载地址:http://www.microsoft.com/downloads/details.aspx?familyid=46F72DF1-E46A-4A5F-A791-09F07AAA1914&displaylang=zh-cn 附记:目前已经可以和VS2005进行联调了,是我的疏忽,没有在PPC确认相关程序的执行! 本文转自yefanqiu51CTO博客,原文链接:http://blog.51cto.com/yfsoft/323819,如需转载请自行联系原作者
/*** Ext.ComponentQuery用法*/Ext.onReady(function() {var panel = Ext.create("Ext.container.Viewport", {items : [{width : 400,height : 300,title : 'panel1',ref : 'panel1',items : [{xtype : 'button',text : 'p1btn1',ref : 'btn1'}, {xtype : 'button',text : 'p1btn2',id : 'btn2',ref : 'btn2'}]}, {width : 400,height : 300,title : 'panel2',ref : 'panel2',items : [{xtype : 'button',text : 'p2btn1',ref : 'btn1'}]}]});// 通过xtype得到组件,如果是多个类别,可以逗号隔开,如:'gridpanel,treepanel'// var items = Ext.ComponentQuery.query('panel,button',panel);// 通过ID获得组件:#ID// var items = Ext.ComponentQuery.query('#btn2',panel);// 获得panel下的所有button,这个需要注意,button必须在panel下的第一层,如果中间跨层是找不到的,如:'viewport>button'是找不到button的,因为中间有一层panel// var items = Ext.ComponentQuery.query('panel>button',panel);// 通过组件的属性来查找// var items = Ext.ComponentQuery.query('button[id=btn2]',panel);/*** 以上是Ext.ComponentQuery使用的几种情况,在ExtJS4中所有的组件都有一个query方法,这个方法就是ComponentQuery的实现。不过,* 我们在开发中真正用的时候,还是用组件的query方法,比较方便。* 还有就是ref属性,这个在extjs4没有了,使得我们操作起来不想以前那么方便了,不过,我们还是可以再这个属性用作在一个容器内,各个组件的唯一标识,这样的话也避免了ID的重复,* 下面我就简单的写一下,如果大家有什么问题,或者是好的方式。欢迎到家给我留言。我们一起学习,共同进步,谢谢。*/// 在容器panel里,通过ref查找panel2下的btn1var items = panel.query('panel[ref=panel2]>button[ref=btn1]');Ext.Array.each(items, function(d) {alert(d.ref + '--' + d.text + '--' + d.getXType());})}) 本文转自yunlielai51CTO博客,原文链接:http://blog.51cto.com/4925054/1310794,如需转载请自行联系原作者
杂谈PPT 文档撰写 说到 PPT ,其实更是一门学问;运用起来说简单也简单,说复杂也是很复杂。工作了很多年了,也先后在不少小型 IT 企业 、大型 IT 企业、跨国 IT 企业中呆过,每个公司的 ppt 的制作的细致程度、优劣, IT 发展水平甚至企业文化都可以在 ppt 中隐隐体现出来,当然不一定完全是正确的。 总体来说外企的 ppt 制作的更为精美、细致,排版布局甚至对 ppt 模板的要求都是规范化的,尤其是产品化的产品文档、产品手册、宣传材料看了令人印象深刻和折服;很难想象出来公司会投入多大的精力去做这些东东。 跨国 IT 企业通常会制定一下 ppt 的制作规范,例如 logo 的运用,色调的搭配、字体的大小,而且舍得投入精力来做这些看似不起眼的事情,比如一张看似简单的网络拓扑图竟然是若干图片的组合,线条的运用,颜色和层次的不同区别;这样的 ppt 姑且不论在技术和内容层面上如何,但是看到这些展示就已经令人印象叹为观止了;内容固然重要,但是形式和包装也是很重要的,我相信一个好的美工和一个系统架构师的作用同样重要。 我现在所在公司确实有不少产品和相当的产品线,内容与市面上的其他产品相差无几,科学的叫法成为产品同质化严重。对于一个普通人来说凭什么选择你而不选择他呢?首先抓住客户的在于对产品的视觉感观,第一时间产品对视觉的冲击,比如界面是否给人印象深刻,色调、布局是否妥当,图标是否丰富等等。很不幸现在的公司没有重视这一块内容,结果就变成了市场的低端产品。 形式之于内容,孰轻孰重?对于行内人士而言看重内容,对于普罗大众来说也许更看重形式吧,不施粉黛固然朴实无华,略施粉黛则彰显魅力,当然粉黛太浓也会适得其反。这个度还是需要的。 内容就像内功,而内功确实非常难练成的,往往需要 3 、 5 年才能小成,几十年才能有大成,对于 IT 企业来说尤其是小型 IT 企业, 1 、 2 年就意味着有生存问题了;不如投机取巧一下,投大众之所好,做一次俗人又何妨,何况形式本身也是一种锻炼内功的机会、。 形式则像外加功夫,如果勤学苦练的话,没准半年或者数月,就可以出去杂耍一下,像模像样的诈唬一下不懂功夫的人还是很有作用的;我们公司的网站 cnlist ,相信大部分股民也都知道这个网站,样貌平平,形同鸡肋,内容很全,像一堆资料的堆砌,看不出来重点,看了不知所云,不看呢又少了一份重要的资讯来源。我曾经提供建议,能否请个高级美工,把 cnlist 改版一下,把公司的产品重新美化一下,无奈人微言轻,没人推动,答曰公司重心不在于此。区区几个人月就能做好的事情,不一定非要来个惊天动地的颠覆吧。 话题越扯越远,变成内容和形式的关系了。 J 内容是重点,当然形式也不全是点缀; ppt 的撰写与个人性格也有很大关系,对于不善言辞的技术人员来说,我主张写的越多越好,尤其像我这样的人,胆子有比较小,看到一群观众的时候往往会不知所措,不妨把你要表达的东西写到 ppt 上,不至于无话可说;对于善于忽悠的售前、市场人员和资深的技术人员来说当然可以写的精炼一些, ppt 上只要表达重点即可, 1 、 2 、 3 写的简明扼要,很多售前、市场人员能对着一张 ppt 能滔滔不绝讲上半个小时,资深技术人员因为已经了然于胸,可以海阔天空任意发挥,对此我只能采取敬仰的态度了。 ppt 的页码取决于个人性格,也取决于客户的偏好,当然客户的偏好,我们也很难去把握,那就折中一下,一般 ppt 控制在 30 页左右,讲上 1 个小时 ~1.5 小时为宜,然后留上半个小时做疑难解答。 至于内容的顺序呢。通常的做法是 第一部分论述原有的情况和存在的问题,当然也不要把用户贬的一无是处。 第二部分论述新的做法能够解决哪些问题,短期、中期、长期的目标 第三部分主要是相信的功能性描述 第四部分主要是一些方法论的东西,尽管虚无缥缈,却是必不可少的环节,尤其是老外的东西,忽悠你没商量;在这方面我们与国际上还有相当大的差距。 第五部分是公司的介绍和相关的案例。 第六部分就是一般的寒暄了。 暂时写到这吧,以后有什么灵感会再慢慢补充起来。 ppt 撰写的经验分享 原文地址:http://groups.google.com/group/ttnn/browse_thread/thread/a5e1deed95eb16da 春节前的日子,没多少具体工作。下周的大部分时间,都要进行项目组培训和交流。有一下午是我的,其中一块是分享ppt 撰写的经验。在ttnn 以前曾经感悟http://groups.google.com/group/ttnn/browse_thread/thread/1010d0cac5defdd3 . 过这个问题,正好,借此机会也是整理完善一下。今天一天都在撰写这份关于ppt 的ppt ,中午,来将思路再明晰一下。 最近五年,ppt 写了不少,有长进。经常也看看别人的设计 ,比如slideshare 这里有不少很好的作品。有些理念,理解并实践了,有些还没形成习惯,对没有习惯的,不多说。比如关于ppt 的彩排,有人强调这个,但我一直都没养成习惯,所以,不说了。 以下基本按照预想的ppt 提纲来表述。 一、楔子 6Jw3Q8YJ4Q8?B6517 世界上有3 亿powerpoint 用户,每天有3 千万的ppt 产生,就在此刻,会有1 百万的ppt 正在进行。但,它们中的50% 都起不到效果,作无用功。 为什么呢?因为大部分ppt 都缺少中心思想,缺少叙述逻辑,缺少好的表现形式。在这份ppt 里面,将主要强调关于这些的ppt 设计思维,以及在这些思维之下的实战经验。 二、思维篇 $m,f+[I\+?5u6517 思维篇将主要讲述ppt 设计的一些思想准备。 1 、中心思想 ;zlC:K9gPH5~6517 在撰写一份ppt 之前,人们常常在考虑什么呢?可能经常是," 有什么现成的片子可以用?" 、" 要写多少页?" 、" 有什么模板吗?" 、" 哪里有什么好看的图片?" 、" 用什么字体?" 、" 主要用什么颜色?"... 其实,这些都不是最重要的问题。 先问一下为什么目的来撰写这份ppt ?可能是老板要求写一份材料、可能是客户明天就要汇报、可能是展示我们辛勤的工作成果、或者是建议听众应该采取某种行动... 其实,这些都是要捕获听众的心,去说服他们。写这份ppt 就是为了达到目的,让老板看到下属丰富的工作,让客户的领导看到新的创意,面临的危机,得要让他们看了以后,觉得,哦,真是这么回事,得有所行动啊。行动是什么?给你嘉奖,上一个项目,指定一个营销策略,这就是他们的行动。如果一份ppt 给别人讲了、看了,他过了十五分钟就忘了,那肯定是一个失败的ppt 。 为达到目的,你准备说什么? 很多东西要说,或者感觉没什么可说的?这都是一开始面临的常见情形。假设一个场景。别人拿着手枪指着你的脑袋," 说,告诉我一个理由不杀你,我数5 下。" 你怎么回答,你说,我上有老,下有小,这太老套。你求饶,绕我一命,以后不敢了。你得有个能够让杀手满意的回答,如果你了解事由,知道他是没分清敌我,你可以说," 其实我是卧底。" 当然,这不是现实情况,没有这么极端。但也因此,我们失去很多机会,表达自己想法的机会。人是懒惰的,动脑子的事情其实是很费精力的,宁愿按照某种套路行事,不见棺材不落泪。写ppt 也是一样,如果只是应付,ok ,拼凑一番可以交差。但,那是没有效果的,做无用功的行为。 所以这时候,不论是在开始ppt 之前,还是之后,都需要用一个标准来拷问——" 它是否表明了某个中心思想?" ,他是最重要的,是最能够说服听众的。 有没有那个点?有了,祝贺你,可以继续下去,开始编故事。没有?也很正常... 有一些办法。 可以用头脑风暴的方法。大家坐在一起,讨论究竟要说什么重点?唯一的中心思想是什么?这种方法还是比较有效的,集合多人的头脑,得出一个重点,还算是比较清晰的。或者,可以找个合适的地方,自己一个人呆着,思考思考,从头开始思考听众到底需要什么,换个角度来看待问题。这也许比头脑风暴有更好的效果。但就是孤独一些。 现在有中心思想了吗?还没有?继续想吧。不过,说要有中心思想,到并不是" 完全正确" 的中心思想,这可不容易,这里只是强调" 得有" 。可以先形成一个想法,去顺着这个想法编故事,然后发现想法不对,再重新修正想法。总之,中心思想就是能够用简短的语句,例如30 字左右的句子,将你要说的东西表达出来。 2 、编故事 u RaNS PY6517 假设你已经有了那个中心思想了吧。接下来要做的是编故事,要用一个故事剧本来演绎那个思想。就像电影一样。现在需要的是一个好的结构和素材。 结构,得符合逻辑。拿电影来做比喻,总也是平铺直叙、倒叙、穿插之类的结构,但总归是符合逻辑的。就是是科幻的,比如matrix 那样的片子,也得符合逻辑,再怪异的事情也得用逻辑来串连。就算" 无厘头" 式的电影,好像没有逻辑,但主线也是逻辑的,比如穷小子奋斗赢得美人归。而ppt 的主题结构,大致有问题- 解决路径- 结论,有问题- 结论- 原因分析,或者是标新立异的尝试。所以,在解决路径或者原因分析里面,逻辑得包含其中,如果你要说明" 明天有雨" 的观点,却用" 去年的销售业绩猛增" 来证明,这就有些无厘头了。除了有逻辑,逻辑还得简单,证明一个观点,你一下子抛出6 个原因,恐怕没人信了。其实恐怕只有一个关键原因是人们愿意相信的。 结构的组织要通过素材的选择,也许你手头上有不少素材,也许只有很少的素材。巧妇难为无米之炊。 这时候,也可以通过头脑风暴的方法来搜集素材。搜集了不少想法,然后,去掉跟中心思想无关的素材,这时候一定得舍得下手。然后将备选的素材联接起来。这种联接是层次的,反映中心思想的,有2-3 个观点,放映其中某个观点的,也是2-3 个原因... 一段精彩的故事,得是充满新鲜素材的,逻辑严谨的,这会让中心思想产生说服力。 3 、表现形式 -? fG5^Y})|)J8Q6517 要寻找一个中心思想,要编一段精彩的故事。 需要一种新的表现形式,需要重新审视我们目前的表现形式是否讨人喜欢,听众是否愿意接受。 " 一切都要尽可能简单,但也不要太简单!" 这是爱因斯坦说的,我到不明白他说这句话的实际含义。但我一直信奉" 简洁" 这个原则,ppt 是一种用于说服别人的工具,每个人只能接受简单的东西。所谓简单,就是指在交互这个层面,而不论内部是多么复杂。因此,翻译成简洁可能更加好听一下。 简洁,就为了让听众更快地接受你传达的信息,将要表达的观点,图形化思考,别讲页面做成提词机、数据表格之类的,将他们转换成图形,并突出表达观点的地方。简洁的原则,内涵包括:每页一个观点、很少的颜色、单一的字体、很少的文字、尝试用会意性图片。 将那些旧有习惯,先抛开,哪怕你后面还是用得着。比如受模板的限制,这是个很大的障碍,常常会被这些东西限制。比如默认的模板、字体、要求的每页讲多少分钟的限制,包括powerpoint 的技术限制,等等,这都是一种对表达中心思想的束缚,先抛开他们。 先拿起纸和笔,在上面图形化表达你的思路。 三、实战篇 2kv V5tu8g7O wVc6517 实战篇将主要讲述在写ppt 时候形式上面的一些技巧的注意方面。形式上的,其实可以分为功能性和美观性,其实很多形式上的东西是功能性,而非美观性,美观性是怎么看着漂亮,功能性是怎么样更容易让信息被听众接受。在下面的介绍里面,是更加强调功能性的。 主要从布局、用词、图形化表示、风格、字体、色彩六个角度来说事儿。风格、字体和色彩,其中包括了一些美观性经验,也有功能性的。其他方面主要是功能性的。 1 、布局ITPUB个人空间6aF-J2OV6h 布局是指一个页面的大致印象。 少是需要的。不要让页面充满太多的元素,宁可将一些元素合成一个元素,再另起一页来详述它。要知道,你将详细的结构放在一页,但其实,这个信息很可能传递不到听众那里,不仅是浪费,而且是干扰。 整洁也是需要的,文字、图得组织的大块区域,一般不要让页面超过四大块,这样让内容清晰便于理解。而且,文字、框框不要犬牙交错,显得很不用心。 2 、用词ITPUB个人空间)m4@RG#Oh?9l X&Y 用词方面,是指如何编写文字。 常见的初学者会从word 里面贴上一大段文字,这种做法不行。ppt 跟word 的目的不同。要对这些段落进行一些修改。不要长篇大论,对他们进行分段、分行、去掉连接性词语。比如" 我们认为.." 、" 在这种情况下..." 、" 根据上图..." 之类的。 将一段句子,分成可以一眼扫过去觉得清晰的几行,然后用颜色和字号来突出关键词语。比如" 价值提升了34%" ,要强调提升效果,就将34% ,标红、标粗,甚至可以放大字号。 3 、图形化表示 :r K9p;E,h xokd6517 图形化表示是将文字观点,用图形表示。 文字之间是有关联性的,比如因果、顺序、层次等等,用文字的项目符号,无法传达这种信息。要将文字要素提取出来,选用合适的图形组合来表达。在麦肯锡、埃森哲等咨询公司里面,多有这种模板。但其实,那也是一种限制。更重要的是理解文字要素背后的逻辑关系。然后去寻找图形,甚至是自己绘制图形,都不是费力的事情。比如要表明一种此消彼长的关系,可以用天平,简单用直线、三角形,就可以组成一个天平的样子。 感悟屁屁体 原文地址: http://groups.google.com/group/ttnn/browse_thread/thread/1010d0cac5defdd3 大家都写过PPT 吧,它是一种非常不错的工具,用来简单地表达自己的观点。我最近几年写了不少,多写写还是有长进的,翻开以前的ppt ,跟现在的对比,能够看到不少差距。主要的差距就在于—— 你是否表达了什么。 以前,不知道要表达什么,一锅粥;现在,明显有表达的意识。 表达观点,是ppt 核心的东西。ppt 一般是用在商业环境里面的,很少是用来表达情绪的。所以,ppt 跟写诗、写散文不一样。表达观点,得有对象,说给什么人听,而散文和诗之类的,你可以写自己的感悟,甚至就是写给自己看都没关系。但ppt 很少如此,总得有听众,需要将你的核心观点传递给他们。 一点点细微的差别,是传递信息还是表达自我,要从中作出判断都不容易。不过可以说,对疏于表达观点的人来说,当他开始写ppt ,大多都是在表达自我—— 将自己心里想的东西一股脑儿倒出来,太多?没关系,一条一条列出来就可以。我以前写ppt 的时候,是这个习惯,现在想想,真是不好意思,如今看到很多ppt 也是这个毛病,其症状都是,不知道要说什么,不知道其中的逻辑是什么,不知道想突出的重点是什么。 以前,遇到写ppt 的事情,很简单,回去就动手,完了拿到客户那里一看,不对,不是这个意思。于是再修改。还好,那时候我脸皮比较厚,心中早就预着修改三次才得到终稿,也无所谓。不过后来发现,其实根本没有必要去做那些无用功,要在第一稿拿出一个思路清晰、逻辑严谨的版本就不需要浪费开始的脑力了。当然,大家也不要以为这样可以省去很多事情。当你的第一个版本质量高了以后,要求也就高了,事情可能更多,但这是另一回事儿,不在本文探讨范围之内。有了这个想法以后,我觉得提纲是非常之重要。其实从小语文老师就教导要写提纲,我一直觉得提纲都很好写,只需要一二三列出来就可以了。这样列提纲跟没列一样,除了一二三这种形式性的条款,还有更重要的事情,就是检验这个提纲:每一点之间的逻辑关系是否合理,整体上是否突出了重点表达的东西。有时候,写ppt 的人跟讲ppt 的人不是一个人,这时候更得把提纲拎出来检验。 前些日子我层提到收到过十二份营销案例评比ppt 的需求。在动手之前便要求讨论提纲。用头脑风暴的方式,得模拟场景,得站在听众的角度去理解,看能不能接受。由于好消息和坏消息的结合,那次,我们实际并不需要写那么多,但一个下午还是对每个提纲展开风暴,倒也有些收获,发现了不少点子,可以留作以后的弹药。 至于风格问题,是有个人偏好的。有的人喜欢简洁,有的人喜欢复杂。有的人对字体选择、颜色很敏感,有些人根本全是默认的。对于那些在ppt 上堆满了很多字的页面,总是有些让人头疼。刚才说写ppt 跟写诗不一样,其实在这里,竟然还有些相通。至少在形式上,要简短,不要一些垃圾词汇,比如" 而且" ," 数据显示…" 之类的废话。更多地,还是要用图形化的语言来说明,毕竟ppt 不是word 。不过对于风格问题,我还是觉得不能强求。 曾经看过一篇讲述如何完成一份优秀的ppt 的片子,作者提出三个观点:ITPUB个人空间 U7E)U5K7^jD v 1 、 抛弃旧的习惯; xr*sG*DM6517 2 、 传递一个信息; GkA6}D0i8n\{V6517 3 、 讲述一个故事; 我倒是认为他应当将第2 点放在第1 点更合理," 一个信息" 是核心的东西,而旧的习惯,是一种阻碍你表达的东西,而故事,则是优化你表达的途径。后两者,都是风格问题。 不强求风格的原因,是因为这跟听众有关系。如果听众根本不能接受简洁的页面,会认为你没费心思,会让你感到有些不爽。当然,如果你有那个自信,你传递了清晰的观点有另当别论。如果听众不喜欢朴素的页面,也许他更喜欢色彩丰富的模样。或者,他对ppt 有不同的期望,他希望ppt 是可以用来看的,而不是用来听你讲的,所以,ppt 上最好是有很多文字,不用你去给他讲解。风格没有绝对的,只是你是否能够有自信贯穿自己的风格,你可以用大红大绿的配色,如果你认为这是你的风格,我觉得问题不大。 我个人偏向于简洁一点的风格,这样有很多好处。可以专注在内容方面,而尽量用一些基本的要素,比如带圆角的方框、箭头。用不同颜色、线条粗细不让页面过于呆板。而对于一些ppt 模板里面拷贝出来的图形元素,如多种图形组合起来,有光影效果的圆球之类的,还是慎用。因为要不你得用一套,以保持页面的一致性,要不你修改起来特麻烦,浪费时间。在此,我认为上面三点中,抛弃旧习惯对形成风格是有很大帮助的。确实,我们平常很多时候都在遵从模板化的东西,从别人那里借用。与其如此,到不如尝试一下,抛开那些条条框框,只是为了你要表达的观点。 本文转自baoqiangwang51CTO博客,原文链接:http://blog.51cto.com/baoqiangwang/312984,如需转载请自行联系原作者
Internet 打印提示“打印机安装失败、打印机名称无效”的解决 解决方法: 打开Internet选项,将打印服务器的网址增加到可信任站点,同时将安全级别调整为低 本文转自ycrsjxy51CTO博客,原文链接:http://blog.51cto.com/ycrsjxy/924106,如需转载请自行联系原作者
.可以使用Transact-SQL中的CREATE PROCEDURE语句创建存储过程,使用该语句的语法为: 2.在查询分析器中执行如下语句创建一个存储过程。 3.在企业管理器中创建存储过程的方法为,展开相应的数据库sample,在“存储过程”节点上右击鼠标,在弹出的菜单中选择“新建存储过程”命令。 4.在创建存储过程的窗口中,“文本”文本框中显示了新建存储过程的模板文本。 5.在“文本”文本框中输入创建存储过程的SQL语句,如下图: 6.要检查定义存储过程的语句是否有误,可以点击”检查语法”按钮,下面的窗口显示了该SQL语句没有错误。 7.通过本例我们学习了如何创建存储过程。 ***************************************************** 上接SQL2K数据库开发二十五之索引操作删除索引 下接SQL2K数据库开发二十七之存储过程操作创建存储过程(二) 本文转自redking51CTO博客,原文链接:http://blog.51cto.com/redking/66489,如需转载请自行联系原作者