星期四, 三月 16, 2006

高级应用 java多线程设计模式详解之一

  1.线程的创建和启动
  
  java语言已经内置了多线程支持,所有实现Runnable接口的类都可被启动一个新线程,新线程会执行该实例的run()方法,当run()方法执行完毕后,线程就结束了。一旦一个线程执行完毕,这个实例就不能再重新启动,只能重新生成一个新实例,再启动一个新线程。
  
  Thread类是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法:
  
  Thread t = new Thread();
  t.start();
  
  start()方法是一个native方法,它将启动一个新线程,并执行run()方法。Thread类默认的run()方法什么也不做就退出了。注意:直接调用run()方法并不会启动一个新线程,它和调用一个普通的java方法没有什么区别。
  
  因此,有两个方法可以实现自己的线程:
  
  方法1:自己的类extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。例如:
  
  public class MyThread extends Thread {
  public run() {
  System.out.println("MyThread.run()");
  }
  }
  
  在合适的地方启动线程:new MyThread().start();
  
  方法2:如果自己的类已经extends另一个类,就无法直接extends Thread,此时,必须实现一个Runnable接口:
  
  public class MyThread extends OtherClass implements Runnable {
  public run() {
  System.out.println("MyThread.run()");
  }
  }
  
  为了启动MyThread,需要首先实例化一个Thread,并传入自己的MyThread实例:
  
  MyThread myt = new MyThread();
  Thread t = new Thread(myt);
  t.start();
  
  事实上,当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用target.run(),参考JDK源代码:
  
  public void run() {
  if (target != null) {
  target.run();
  }
  }
  
  线程还有一些Name, ThreadGroup, isDaemon等设置,由于和线程设计模式关联很少,这里就不多说了。
  
  2.线程同步
  
  由于同一进程内的多个线程共享内存空间,在Java中,就是共享实例,当多个线程试图同时修改某个实例的内容时,就会造成冲突,因此,线程必须实现共享互斥,使多线程同步。
  
  最简单的同步是将一个方法标记为synchronized,对同一个实例来说,任一时刻只能有一个synchronized方法在执行。当一个方法正在执行某个synchronized方法时,其他线程如果想要执行这个实例的任意一个synchronized方法,都必须等待当前执行synchronized方法的线程退出此方法后,才能依次执行。
  
  但是,非synchronized方法不受影响,不管当前有没有执行synchronized方法,非synchronized方法都可以被多个线程同时执行。
  
  此外,必须注意,只有同一实例的synchronized方法同一时间只能被一个线程执行,不同实例的synchronized方法是可以并发的。例如,class A定义了synchronized方法sync(),则不同实例a1.sync()和a2.sync()可以同时由两个线程来执行。
  
  3.Java锁机制
  
  多线程同步的实现最终依赖锁机制。我们可以想象某一共享资源是一间屋子,每个人都是一个线程。当A希望进入房间时,他必须获得门锁,一旦A获得门锁,他进去后就立刻将门锁上,于是B,C,D...就不得不在门外等待,直到A释放锁出来后,B,C,D...中的某一人抢到了该锁(具体抢法依赖于JVM的实现,可以先到先得,也可以随机挑选),然后进屋又将门锁上。这样,任一时刻最多有一人在屋内(使用共享资源)。
  
  Java语言规范内置了对多线程的支持。对于Java程序来说,每一个对象实例都有一把“锁”,一旦某个线程获得了该锁,别的线程如果希望获得该锁,只能等待这个线程释放锁之后。获得锁的方法只有一个,就是synchronized关键字。例如:
  
  public class SharedResource {
  private int count = 0;
  
  public int getCount() { return count; }
  
  public synchronized void setCount(int count) { this.count = count; }
  
  }
  
  同步方法public synchronized void setCount(int count) { this.count = count; } 事实上相当于:
  
  public void setCount(int count) {
  synchronized(this) { // 在此获得this锁
  this.count = count;
  } // 在此释放this锁
  }
  
  红色部分表示需要同步的代码段,该区域为“危险区域”,如果两个以上的线程同时执行,会引发冲突,因此,要更改SharedResource的内部状态,必须先获得SharedResource实例的锁。
  
  退出synchronized块时,线程拥有的锁自动释放,于是,别的线程又可以获取该锁了。
  
  为了提高性能,不一定要锁定this,例如,SharedResource有两个独立变化的变量:
  
  public class SharedResouce {
  private int a = 0;
  private int b = 0;
  
  public synchronized void setA(int a) { this.a = a; }
  
  public synchronized void setB(int b) { this.b = b; }
  }
  
  若同步整个方法,则setA()的时候无法setB(),setB()时无法setA()。为了提高性能,可以使用不同对象的锁:
  
  public class SharedResouce {
  private int a = 0;
  private int b = 0;
  private Object sync_a = new Object();
  private Object sync_b = new Object();
  
  public void setA(int a) {
  synchronized(sync_a) {
  this.a = a;
  }
  }
  
  public synchronized void setB(int b) {
  synchronized(sync_b) {
  this.b = b;
  }
  }
  }


星期三, 三月 15, 2006

一些学习笔记,给自己看的,备忘

1.声明数组的一种方式:

int * data; //定义一个指针

int size = 8;

data = new int[size]; //该指针是数组的引用

int* data;

data = new int ;new符用以动态分配内存,后续可以:

data[i] = i;

2.C++中声明常量的方法有两种:

A #define Num

B const char* c= “friend”;

3.char * s = “12345n” = char s[] = “12345”

Cout<<s 结果是12345

Cout<<*s cout<<s[0]结果都是1

int* i[] = {1,2,3,4,5}

cout<<i 结果是 地址

cout<<i[0] 结果是1

4. printf 探讨

原型:extern void printf(const char *format,...);

用法:#include <stdio.h>

功能:格式化字符串输出

说明:format指定输出格式,后面跟要输出的变量

目前printf支持以下格式:

%c 单个字符

%d 十进制整数

%f 十进制浮点数

%o 八进制数

%s 字符串

%u 无符号十进制数

%x 十六进制数

%% 输出百分号%

一个格式说明可以带有几个修饰符,用来指定显示宽度,小数尾书及左对齐等:

- 左对齐

+ 在一个带符号数前加"+""-"

0 域宽用前导零来填充,而不是用空白符

域宽是一个整数,设置了打印一个格式化字符串的最小域。精度使用小数点后加数字表示的,

给出每个转换说明符所要输出的字符个数。

注意:带修饰符的显示可能不正常

举例:

// printf.c

#include <stdio.h>

#include <system.h>

main()

{

int i;

char *str="GGV";

clrscr();

textmode(0x00);

printf("Printf Demo-%%c");

printf("--------------");

printf("%c-%c-%c-%cn",'D','e','m','o');

printf("%2c-%2c-%2c-%2cn",'D','e','m','o');

printf("%02c-%02c-%02c-%02cn",'D','e','m','o');

printf("%-2c-%-2c-%-2c-%-2cn",'D','e','m','o');

getchar();

clrscr();

textmode(0x00); // not nessary

i=7412;

printf("Printf Demo-%%d");

printf("--------------");

printf("%dn",i);

printf("%14d",i);

printf("%+10dn",i); // output format not correct(bug)

printf("%-10dn",i);

getchar();

clrscr();

printf("Printf - d,o,x");

printf("--------------");

printf("%dn",i);

printf("%on",i); // %o and %x not implemented

printf("%xn",i);

getchar();

clrscr();

printf("Printf Demo-%%s");

printf("--------------");

printf(" %sn","Demo End");

printf(" %sn","Thanx");

printf(" %sn %s","Golden","Global View");

getchar();

return 0;

}

5. fread函数和fwrite函数

size_t fread(void *buffer, size_t size, size_t count, FILE *fp):从文件fp中读入count

,每次读size字节,读入的信息存在buffer指针指向的缓冲区。函数返回值等于实际读入的次数(可能少于count)。

size_t fwrite(void *buffer, size_t size, size_t count, FILE *fp):将buffer地址开始

的信息,写入count次,每次写size字节至文件fp中。函数返回值等于实际写入的次数(可能少于count)。

[例]、结构体类型数据。

  struct student_type

  {

   char name[10];

   int num;

   int age;

   char addr[30];

  }stu[40];

写入文件:

 for(i=0; i<40; i++) /* 每次写一个学生 */

  fwrite(&stu[i], sizeof(struct student_type), 1, fp);

  或:写一次

  fwrite(stu, sizeof(struct student_type), 40, fp);

从磁盘文件读出:

  for(i=0; i<40; i++)

  fread(&stu[i], sizeof(struct student_type), 1, fp);

  或:

fread(&stu[i], sizeof(struct student_type), 40, fp);

使用时是fopenfread fclose 不要忘记释放内存

例如:

FILE * stream;

int i;

stream = fopen(“/tmp/fwrite”,”r”);

fread(s,sizeof(struct test),nmemb,stream);

fclose(stream);

6.trim()

这是去掉空格函数

S = rs.getStream(number1).trim();

这是java中使用的方法,C/C++ 中的使用略有不同,要带参数,但都是小小菜

其中有一点 number1 不能为null 否则编译将不能通过。

7. 有了malloc/free为什么还要new/delete

mallocfreeC++/C语言的标准库函数,new/deleteC++的运算符。它们都可用于申请动态内存和释放内存。

对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free

因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。

例子

Obj *a = (obj *)malloc(sizeof(obj)); // 申请动态内存

a->Initialize(); // 初始化

//…

a->Destroy(); // 清除工作

free(a); // 释放内存

void UseNewDelete(void)

{

Obj *a = new Obj; // 申请动态内存并且初始化

//…

delete a; // 清除并且释放内存

}

现在C++中已经很少用第一种方法了


我来解释一下句柄吧

看到好多人在讨论句柄,我也发表一下看法

句柄实际上是一个数据,是一个Long (长整型)的数据

句柄是WONDOWS用来标识被应用程序所建立或使用的对象的唯一整数,WINDOWS使用各种各样的句柄标识诸如应用程序实例,窗口,控制,位图,GDI对象等等。WINDOWS句柄有点象C语言中的文件句柄。

从上面的定义中的我们可以看到,句柄是一个标识符,是拿来标识对象或者项目的,它就象我们的姓名一样,每个人都会有一个,不同的人的姓名不一样,但是,也可能有一个名字和你一样的人。从数据类型上来看它只是一个16位的无符号整数。应用程序几乎总是通过调用一个WINDOWS函数来获得一个句柄,之后其他的WINDOWS函数就可以使用该句柄,以引用相应的对象。

如果想更透彻一点地认识句柄,我可以告诉大家,句柄是一种指向指针的指针。我们知道,所谓指针是一种内存地址。应用程序启动后,组成这个程序的各对象是住留在内存的。如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访问对象。但是,如果您真的这样认为,那么您就大错特错了。我们知道,Windows是一个以虚拟内存为基础的操作系统。在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要。对象被移动意味着它的地址变化了。如果地址总是如此变化,我们该到哪里去找该对象呢?

为了解决这个问题,Windows操作系统为各应用程序腾出一些内存储地址,用来专门登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。Windows内存管理器在移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。这样我们只需记住这个句柄地址就可以间接地知道对象具体在内存中的哪个位置。这个地址是在对象装载(Load)时由系统分配给的,当系统卸载时(Unload)又释放给系统。

然而在我们实际编程中又是怎样使用句柄的呢?

句柄概念在WINDOWS编程中是一个很重要的概念,在许多地方都扮演着重要的角色。但由此而产生的句柄概念也大同小异,比如:<<Microsoft Windows 3 Developer's Workshop>>(Microsoft Press,by Richard Wilton)一书中句柄的概念是:在Windows环境中,句柄是用来标识项目的,这些项目包括:

*.模块(module)

*.任务(task)

*.实例(instance)

*.文件(file)

*.内存块(block of memory)

*.菜单(menu)

*.控制(control)

*.字体(font)

*.资源(resource),包括图标(icon),光标(cursor),字符串(string)

*.GDI对象(GDI object),包括位图(bitmap),画刷(brush),元文件(metafile),调色板(palette),画笔(pen),区域(region),以及设备描述表(device context)

WINDOWS程序中并不是用物理地址来标示一个内存块,文件来动态装入的,相反,WINDOWS API给这些项目分配确定的句柄,并将句柄返回给应用程序,通过句柄来调用

一个WINDOWS应用程序可以用不同的方法获得一个特定项的句柄。许多API函数,诸如CreateWindow,GlobalAlloc,OpenFile的返回值都是一个句柄值。另外,WINDOWS也能通过应用程序的引出函数将一个句柄作为参数传送给应用程序,应用程序一旦获得了一个确定项的句柄,便可在WINDOWS环境下的任何地方对这个句柄进行操作。其实句柄的大量使用已经影响到了每一个WINDOWS的程序设计。

句柄只有当唯一的确定了一个项目的时候,它才开始有意义。句柄对应着项目表中的一项,而只有WINDOWS本身才能直接存取这个表,应用程序只能通过API函数来处理不同的句柄,举个例子来说吧!比如:我们可以为我们的应用程序申请一块内存块,通过调用API函数GlobalAlloc,来返回一个句柄值:

hMem = GlobalAlloc(……);

其实现在的hMem还只是一个索引值,不是物理地址,应用程序还不能直接存取这块内存,在这里顺便提一下,通常我们在编程的时候,分配的内存块都是随意丢弃的,这样来充分利用有限的内存资源,所以某一个项目被分配到那块内存上是不确定的,因为可以移动所以先锁定那块内存,这是需要应用程序调用API函数GlobalLock来锁定句柄:

lpMem = GlobalLock(hMem);

这样应用程序才能存取这块内存。

其实我们为了理解可以这样认为:它类似于门把手,有它你可找到“门”这个对象,就可以控制对象"",但觉得把它类比于门把手似乎并不十分贴切,感觉象是直译句柄这个词的词意,哈哈

我想现在大家已经能对句柄概念有所了解了,我希望我的文章能对大家有所帮助。其实如果你学过SDK编程,那对句柄的概念理解会更好,更深。如果你是直接学VC6MFC编程的,建议你看一下SDK编程,这会对你大有好处。

作者 徐旭


星期一, 三月 13, 2006

TCAP 事物处理能力

1 概述 TCAP在SS7协议族里的位置:

看到两句话,大概明白了TCAP的作用,和为什么要有TCAP这一层.
1.) Transaction Capabilities Application Part
TCAP enables the deployment of advanced intelligent network services by supporting non-circuit related information exchange between signaling points using the SCCP connectionless service.

2.) TCAP用户,即为各种应用的共同特点就是"交换机需要与网络中的数据库联系.TCAP为它们之间提供信息请求,响应的对话能力.

2 TCAP的功能

TCAP由两个子层组成。成份子层和事务处理子层。

成份子层(Component Portion):传送远端操作及响应的协议数据单元。提供:对话处理和成份处理。

事务处理子层(Transaction Portion):处理两个TCAP用户之间包含成份的消息交换。

3 TCAP消息和参数

消息类型标签
消息总长度

Contents:

事务处理部分信息单元

对话部分信息单元

成份部分标签
成份部分长度
成份1类型标签
成份1长度
成份1部分信息单元

。。。。。。

成份N

事务处理部分消息:

消息
编码
单向消息 Uni-directional
01100001
开始 Begin
01100010
结束 End
01100100
继续 Continue
01100101
中止 Abort
01100111

对话部分消息分两类:对话控制PDU和用户信息。

对话控制定义了两类对话:结构型对话,非结构型对话。
The Dialogue Portion when present consists of one dialogue control protocol data unit or user
information. The dialogue portion is type of EXTERNAL. The direct-reference element of the
EXTERNAL type shall indicate the following abstract syntax name:
{ ccitt recommendation q 773 as (1) dialogue-as (1) version1 (1) }
if structured dialogue is used and:
{ ccitt recommendation q 773 as (1) unidialogue-as (2) version1 (1) }
if unstructured dialogue is used, the data value shall be one of the defined dialogue control protocol
data units.
User information when present shall be identified by a user defined abstract syntax name.

成份部分消息:

消息
编码
Invoke
10100001

Reture-Result (Last)

10100010
Reture-Result ( not Last)
10100111
Reture-Error
10100011
Reject
10100100

一个TCAP消息的例子 主叫用户拔叫800用户号,触发位于交换局(图中SSP)内的路由应用程序向SCP发出一个TCAP查询。

从SCP返回一个与800号码对应的本地用户号给SSP,事务处理就结束了。

4 TCAP的程序

1.) 寻址
在应用无连接网络业务的SS7系统中,TCAP采用SCCP提供的寻址方案。


星期三, 三月 08, 2006

祝福光子,黑子,老五,尖蛋,业功!~

祝福光子,黑子,老五,尖蛋,业功!~

祝贺尖蛋,业功的成功,尖蛋的400多分能够轻松拿个公费,关键是选一个好的导师,业功也已经被本科录取,这是你这两年来不懈努力的结果,我们都很为你高兴。四哥和五哥都是310多分,在今年的形势下,说实在的,不容乐观,不管怎样,四哥考研心里有数,五哥又是考本校,国家线还没下来,一切尚是未知,剩下的时间就要好好把握了。光子的分数不理想,没办法,不希望你像我一样优柔寡断,无论是调剂,工作,还是申请出国,希望你能挺过去,前面的路是光明的,就看自己怎么走,在这春暖花开的日子里,祝愿你能尽快走出阴霾,重见蓝天!~

祝福五个好兄弟,多多保重!~


星期四, 三月 02, 2006

谈一下sizeof

最近在论坛里总看到有人问关于sizeof的问题,并且本人对这个问题也一直没有很好的考虑过,索性今天来个了断,也结合strlen进行比较,如果能对网友有一点点帮助,也算是有点功劳吧,

好首先看看sizeofstrlenMSDN上的定义:来看MSDN上如何对sizeof进行定义的:

sizeof Operator

sizeof expression

The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type

(including aggregate types). This keyword returns a value of type size_t.

The expression is either an identifier or a type-cast expression (a type specifier enclosed in

parentheses).

When applied to a structure type or variable, sizeof returns the actual size, which may include

padding bytes inserted for alignment. When applied to a statically dimensioned array, sizeof

returns the size of the entire array. The sizeof operator cannot return the size of dynamically

allocated arrays or external arrays.

然后再看一下对strlen是如何定义的:

strlen

Get the length of a string.

Routine Required Header

strlen &lt;string.h&gt;

size_t strlen( const char *string );

Parameter

stringNull-terminated string

Libraries

All versions of the C run-time libraries.

Return Value

Each of these functions returns the number of characters in string, excluding the terminal

NULL. No return value is reserved to indicate an error.

Remarks

Each of these functions returns the number of characters in string, not including the

terminating null character. wcslen is a wide-character version of strlen; the argument of

wcslen is a wide-character string. wcslen and strlen behave identically otherwise.

首先看,我用红笔标出来的两句话,第一句是指sizeof 求出来的长度是所有的长度,也就是说包含字符串的结束符,而第二句则说明了strlen求出来的字符串长度是不包含字符末尾的结束符的。而且要注意,sizeof是运算符,strlen是函数。

由几个例子说开去。第一个例子:假设内存中是32

char* ss = "0123456789"; ss是指针

sizeof(ss) 结果是4ss是指针,所以是4个字节

sizeof(*ss) 结果是1,指的是第一个字节

char ss[] = "0123456789";

sizeof(ss) 结果是11,因为char ss[]也是声明一个字符串,所以求得还是字符串ss的长度,况且结束符也算在内。

sizeof(*ss) 结果为1同上

char ss[100] = "0123456789";

sizeof(ss) 结果100 同上但结束符在数组内,包括空字节

strlen(ss) 结果为10 strlen是个函数内部实现是用一个循环计算到为止之前

int ss[100] = "0123456789";

sizeof(ss) 结果为400,每个int类型占用4个字节

strlen(ss) 出错,strlen函数只能求字符串,原形为extern int strlen(char *s);

char q[]="abc";

char p[]="an";

sizeof(q),sizeof(p),strlen(q),strlen(p);

结果是 4332

再看一个例子 sizeof()用类作参数

X{

int i;

int j;

char k;

};

X x;

cout&lt;&lt;sizeof(X)&lt;&lt;endl; 结果 12 内存补齐

cout&lt;&lt;sizeof(x)&lt;&lt;endl; 结果 12 同上

总结一下就是sizeof是算符,strlen是函数。

sizeof可以用类做参数,如上例,输出是所占内存空间的总合,strlen只能用char*做参数,且必须是以''''结尾的。sizeof还可以用函数做参数,比如: short f();

printf("%dn", sizeof(f()));

输出的结果是sizeof(short),即2

数组做sizeof的参数不退化,传递给strlen就退化为指针了

虽然还有好多,但就一般程序员来说,这也足够了吧,只有大师才去想的那么深

谈一下java中的问题

javac++更灵活,使用sizeof()这个函数的时候谁都会觉得很方便,但使用完了以后,没有谁会每次都记得释放内存,一段小程序也许无所谓,但应用到大项目中去就很所谓了,c++程序员要考虑得更多!java思想也已经很完美了,自动释放垃圾内存,况且java的基本数据类型在机器中都是等长的,这也是java跨平台的原因啊,呵呵,现在java这么流行,也是因为做web做网络有其不可抗拒的优势啊

好了,先讨论到这里吧,在公司呆得太晚了,该回去了


星期一, 二月 27, 2006

BufferedReader类的一点心得

最近在网上看了一篇帖子,是问有关BufferedReader类的一些问题,程序代码如下:

import java.io.*;
class Test {
public static void main(String arg[])throws IOException{

InputStreamReader isr = new InputStreamReader(System.in); // InputStreamReader
类的一个对象接收输入System.in
BufferedReader br = new BufferedReader(isr);//
接收输入存至缓冲区,参数是System.in
int c;
while((c = br.read()) != -1){
String s = br.readLine();
System.out.println(s);
}
}
}

该程序是为了接收一串输入然后将其打印至屏幕,出现的问题是打印出来时第一个字符不见了。

其实问题的原因很简单,程序中判断字符是否已经完全打印的语句

while((c = br.read()) != -1)

在第一次执行的时候已经读了一个字符出来,然后光标就会后移一位,接下来的循环中s=br.readLine();读到的就只是后续的字符串了,因此会少一个字符,解决的方法也不难,把判断条件改掉就是了

我做了一下小小的改动便可解决

import java.io.*;
class Test {
public static void main(String arg[])throws IOException{

InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
int c;

do{

String s = br.readLine();

System.out.println(s);

}while(c = br.read()!=-1);

}

}

上面这个程序就可以完成想要的功能了。呵呵

另外,通常在BufferedReader类使用之后都会用一个flush()方法,我看有些网友也有疑问,其实BufferedReader用了一个系统级的缓冲区,只有当缓冲区满了的时候才会输出,如果没有满而又想要操作缓冲区的话,就只能用flush()方法来清空缓冲区,让结果输出,然后操作

JAVA学习每天一点,进步就是很大的了,呵呵,累了,去喝点水


星期五, 二月 24, 2006

智能网络的体系结构

根据我国智能网体制规定,我国的智能网采用基于业务交换点SSP的网络体系。在网中配置了业务交换点SSP、业务控制点SCP、业务数据点SDP、业务管理系统SMS、业务生成环境SCE、业务管理接入设备SMAF和智能外设IP,并通过NO.7信令网组成全国智能网。 业务控制点SCP业务 控制点SCP是智能网络的核心部件,是智能网中业务逻辑和数据集中的控制点。它包括业务控制功能(SCF)和业务数据功能(SDF)两大部分。一个SCP可以处理单一的IN业务,也可以处理多种IN业务。从安全性考虑,SCP及数据库应成对设置,目前我国的智能网建设还处于初期阶段,每个业务用户数据库仅放在一个数据库中,而没有考虑备份数据库。 业务交换点SSP业务 交换点SSP主要负责呼叫控制和业务交换,可以和其他功能实体体系相互通信,获得附加的信息,也可以通过SSP接到业务控制点SCP和业务数据库点SDP。其功能可以在目前任何交换机上通过版本升级和软件修改来实现。从IN业务的组织考虑,SSP设在端局位置最好,但所需的SSP数量较多,并需较长的时间。目前我国智能网的SSP先设在少数长途局,在省内建设时可设在汇接局,并可以做到SSP的逐步下移。 智能外设IP 智能外设IP主要提供智能业务所需的语言提示和数字接收功能。目前IP主要用于传送各种录音通知和接收用户的双音多频信息,而且这些信息是通过SSP接收的,故将IP和SSP放在一起。随着智能网的发展、SSP数量的增多、IP功能的增强,须采用独立的IP。 业务数据点SDP 业务数据点SDP主要用于向用户提供业务所要使用的数据。目前我国的智能网没有引入该设备,而将SDP和SCP放置在一起。 业务管理点SMP 业务管理点SMP主要负责网络管理、业务管理和系统管理。它是整个网络的管理中心,SMP和SCP之间的管理路由是必备的管理路由。通过该路由可以加载新的智能业务到智能网中以及加载新的智能业务用户,修改业务用户的数据,并实现对整个网络的管理。 业务生成环境SCE 业务生成环境SCE是智能网中较关键的节点,是智能网快速、方便、灵活地实现新业务的重要保障。利用独立于应用的模块(SIB)在业务生成环境中,可以方便、快速地提供业务,并将其输入到SMS中。 业务管理接入设备SMAF 业务管理接入设备SMAF主要负责为操作员提供一种接入到业务管理点,以具有对业务和网络进行管理的能力。SMAF常根据业务的需要来设置。 智能网概念模型INCM 由于智能网所服务的网络不同,所提供业务的复杂程度也不尽相同,而且随着通信技术的不断发展会有新的技术及网络出现。为便于智能网提供、生成和管理业务,ITU-T的第11研究组(SG11)计划将智能网分阶段进行研究,就不同阶段提出不同的要求,即对智能网概念模型(INCM)的各个平面(即业务平面SP、总功能平面GFP、分布功能平面DFP和物理平面PHP)及不同实体间的接口规程作出相应的规定,提出相应的建议。

星期一, 二月 20, 2006

MySQL的基本使用--创建数据库和数据库表

1、使用SHOW语句找出在服务器上当前存在什么数据库:

mysql> SHOW DATABASES; 
+----------+ 
| Database | 
+----------+ 
| mysql | 
| test | 
+----------+ 
3 rows in set (0.00 sec)


2、创建一个数据库abccs

mysql> CREATE DATABASE abccs;
注意不同操作系统对大小写的敏感。

3、选择你所创建的数据库
mysql> USE abccs
Database changed
此时你已经进入你刚才所建立的数据库abccs.

4、 创建一个数据库表

首先看现在你的数据库中存在什么表:
mysql> SHOW TABLES;
Empty set (0.00 sec)
说明刚才建立的数据库中还没有数据库表。下面来创建一个数据库表mytable:
我们要建立一个你公司员工的生日表,表的内容包含员工姓名、性别、出生日期、出生城市。

mysql> CREATE TABLE mytable (name VARCHAR(20), sex CHAR(1), 
-> birth DATE, birthaddr VARCHAR(20)); 
Query OK, 0 rows affected (0.00 sec)


由于name、birthadd的列值是变化的,因此选择VARCHAR,其长度不一定是20。可以选择从1到255的任何长度,如果以后需要改变它的字长,可以使用ALTER TABLE语句。);性别只需一个字符就可以表示:"m"或"f",因此选用CHAR(1);birth列则使用DATE数据类型。

创建了一个表后,我们可以看看刚才做的结果,用SHOW TABLES显示数据库中有哪些表:

mysql> SHOW TABLES; 
+---------------------+ 
| Tables in menagerie | 
+---------------------+ 
| mytables | 
+---------------------+


5、显示表的结构:

mysql> DESCRIBE mytable; 
+-------------+-------------+------+-----+---------+-------+ 
| Field | Type | Null | Key | Default | Extra | 
+-------------+-------------+------+-----+---------+-------+ 
| name | varchar(20) | YES | | NULL | | 
| sex | char(1) | YES | | NULL | | 
| birth | date | YES | | NULL | | 
| deathaddr | varchar(20) | YES | | NULL | | 
+-------------+-------------+------+-----+---------+-------+ 
4 rows in set (0.00 sec)


6、 往表中加入记录

我们先用SELECT命令来查看表中的数据:

mysql> select * from mytable;
Empty set (0.00 sec)
这说明刚才创建的表还没有记录。

加入一条新记录:

mysql> insert into mytable 
-> values (′abccs′,′f′,′1977-07-07′,′china′); 
Query OK, 1 row affected (0.05 sec)


再用上面的SELECT命令看看发生了什么变化。我们可以按此方法一条一条地将所有员工的记录加入到表中。

7、用文本方式将数据装入一个数据库表

如果一条一条地输入,很麻烦。我们可以用文本文件的方式将所有记录加入你的数据库表中。创建一个文本文件“mysql.txt”,每行包含一个记录,用定位符(tab)把值分开,并且以在CREATE TABLE语句中列出的列次序给出,例如:

abccs f 1977-07-07 china   
mary f 1978-12-12 usa 
tom m 1970-09-02 usa


使用下面命令将文本文件“mytable.txt”装载到mytable表中:mysql> LOAD DATA LOCAL INFILE "mytable.txt" INTO TABLE pet;

再使用如下命令看看是否已将数据输入到数据库表中:mysql> select * from mytable;

星期日, 二月 19, 2006

为了永恒的战神

我还是很喜欢巴蒂的,虽然我不是特别喜欢巴蒂的打法。在我印象中,典型的阿根廷打法应该是马拉多纳-卡尼吉亚式的,而巴蒂,显然是阿根廷球星的另类。

  巴蒂,感觉就象老朋友一样,青梅竹马那种,看着他长大。有时候和别人聊起,我会说:“巴蒂小时侯…”:)

  小时侯就是他刚出道的那阵了。98年前,记忆中的巴蒂永远是91年美洲杯的少年杀手,巴蒂小时侯和现在大不相同,没现在这么沧桑,很青春的。

  第一次看到“老将巴蒂斯图塔”这几个字让我深受刺激(那是世界杯前)。如果把马拉多纳叫“老马”也就罢了,把巴蒂称为“老将”简直令人无法忍受。巴蒂老了么?是啊,他不知不觉已经29了,虽然我很少去想他的年龄。青春是多么短暂,一个人是多么容易老啊!尽管他是绿茵场上的巨星,仍然不能稍稍减缓时间的脚步。总有一天他会离我们而去的,这一天也不会太远了。总有一天,我们会面对“老将奥特加”,“老将克雷斯波”乃至“老将艾马尔”“老将坎比亚索”。

  91年美洲杯前,很郁闷的说。90年世界杯阿根廷队不但蒙冤输给了德国,还落了个千夫所指的形象;刚进入91年,马拉多纳吸毒案发,惨遭禁赛。阿根廷大厦将倾,一副惨淡景象。

  而巴蒂就在这个时候出现了。

  所以总觉得在最需要的时候,最没有希望的时候,阿根廷就有英雄出世。90年世界杯蓬皮多受伤,却来了戈耶切亚;91年老马出事,巴蒂又带来了美洲杯;94年阿根廷中场告急,奥特加应运而生;98年巴蒂英雄迟暮,帕莱默一鸣惊人......所以我们就可以等待。

  美洲杯当时我是没有看到的,只是一天听新闻说,阿根廷32年后重获美洲杯。后来看了射门集锦,才认识了巴蒂(记得当时和巴蒂齐名的还有个新秀罗德里格斯,后来不知所终)。印象最深的却是巴蒂捧杯时笑容,象阳光一样,灿烂,无忧无虑。

  当时的美洲杯确实也象是满天阴霾中的一线阳光,使没有马拉多纳的阿根廷队又看到了希望。从那时起,阿根廷开始尝试走出马拉多纳的阴影。

  虽然没有了上帝赐予的马拉多纳,凡尘中仍有巴蒂斯图塔。

  我们应该感谢巴蒂。

  美洲杯后,我只知道巴蒂去了意大利一个名字极长极古怪的俱乐部。(当时足球报把佛罗伦萨翻译成费奥伦蒂纳,我的天,我怎么记得住?)他的比赛我看的很少。当时意甲转播翻来覆去就是AC米兰,偏偏我对这种大牌球会有种莫名其妙的逆反心理,所以我看意甲看得很少,更记不住那些大名鼎鼎的球星。

  感觉巴蒂去的那个什么什么纳的俱乐部实力还是不错的,突然有一天,在足球报上看到说是他们要降级了,还登了一张费队的全家福,印刷很糟,但倒还能看得见巴蒂。不过,我永远也忘不了的是那份报道的调侃讽刺的口气,一副幸灾乐祸的嘴脸:“这支胸前印着‘七喜(赞助商)’的球队在以后两周内大概是喜不起来了...”后面又把费队的几大球星嘲笑了一番:(

  可是,他们后来仍然没能避免降级的厄运。

  当时,没想到巴蒂会留下,他离开当然是天经地义的。不过,我也没有太多的吃惊,因为当时年纪小,没见过太多的世俗功利虚伪背叛,认为一切都是情义为重。

  “我看到佛罗伦萨球迷的眼睛,我知道我做的没有错。”多年后巴蒂仍然不悔。也许只有来自潘帕斯草原的巴蒂,真诚坦荡的阿根廷人,才会这样说,这样做。

  91-93年,是巴蒂在国家队最辉煌的时期,不过很遗憾,那时侯还没有体育台,美洲的赛事很少。

  阿根廷当时还是很火的,自从巴西莱上台以后,就没输过球,连续33场国际比赛不败的记录。但我一直都不喜欢巴西莱,觉得他没有主见。

  93年阿根廷以微弱的优势卫冕了美洲杯,两场淘汰赛都是靠戈耶切亚扑救点球过关。卫冕成功却没给我带来太多喜悦(当然如果卫冕失败我会更难受,我还记得那天得知阿根廷夺冠的消息还是十分兴奋,其实那时侯是我最热爱阿根廷的)。因为94年就是世界杯了,想想89年美洲冠军巴西88欧洲冠军荷兰在90世界杯的表现,我多少有点不安。

  然而厄运是猝然而至的。

  阿根廷在世界杯预选赛上本是一帆风顺,那天,放学路上,我习惯性地买了一张“足球报”,“巴西队连胜登榜首阿根廷兵败如山倒”(黑色标题至今历历在目),好象胸口被人捅了一刀,我差点从自行车上栽下来,我甚至没有勇气再去看正文。

  0:5!

  巴蒂当时是上了场的。

  在那天的阴雨绵绵中,我第一次对巴蒂失望了。

  我对巴蒂有些失望,他不是那种力挽狂澜的人。

当时刻意深陷在记忆里的那一段,
本能的突然又想起来,
渐渐也可以一段段地欣赏了。

过去的日子我变了,你也变了,
那个曾经徘徊的身影也随着时光远去了,
一切都如淡淡的云烟,悄悄地散尽、离开了。

多年以后,当故事中的主角已然远离,
那场缘分的相遇又在生命中沉淀成曾经的感动,
悲喜交加的感动……

代表阿根廷足球队出场77次,攻入56个进球,这是战神巴蒂斯图塔留下的纪录。然而岁月无情,在离开球迷视线两年之后,在卡塔尔联赛度日的巴蒂终于向我们道别了。2005年3月13日,这位36岁的前锋,正式宣布退役,结束了他的职业生涯。

巴蒂之狂野美