2009年6月10日星期三

linux select 解释

select系统调用是用来让我们的程序监视多个文件句柄(file
descrīptor)的状态变化的。程序会停在select这里等待,直到被监视的文件句柄有某一个或多个发生了状态改变。

文件在句柄在Linux里
很多,如果你man某个函数,在函数返回值部分说到成功后有一个文件句柄被创建的都是的,如man
socket可以看到"On success, a file descrīptor for the new socket is
returned."而man 2 open可以看到"open() and creat() return the new file
descrīptor",其实文件句柄就是一个整数,看socket函数的声明就明白了:
int socket(int domain, int type, int protocol);
当然,我们最熟悉的句柄是0、1、2三个,0是标准输入,1是标准输出,2是标准错误输出。0、1、2是整数表示的,对应的FILE
*结构的表示就是stdin、stdout、stderr,0就是stdin,1就是stdout,2就是stderr。
比如下面这两段代码都是从标准输入读入9个字节字符:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char ** argv)
{
char buf[10] = "";
read(0, buf, 9); /* 从标准输入 0 读入字符 */
fprintf(stdout, "%s\n", buf); /* 向标准输出 stdout 写字符 */
return 0;
}
/* **上面和下面的代码都可以用来从标准输入读用户输入的9个字符** */
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char ** argv)
{
char buf[10] = "";
fread(buf, 9, 1, stdin); /* 从标准输入 stdin 读入字符 */
write(1, buf, strlen(buf));
return 0;
}

继续上面说的select,就是用来监视某个或某些句柄的状态变化的。select函数原型如下:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout);
函数的最后一个参数timeout显然是一个超时时间值,其类型是struct timeval
*,即一个struct timeval结构的变量的指针,所以我们在程序里要申明一个struct
timeval tv;然后把变量tv的地址&tv传递给select函数。struct timeval结构如下:
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};

第2、3、4三个参数是一样的类型: fd_set
*,即我们在程序里要申明几个fd_set类型的变量,比如rdfds, wtfds,
exfds,然后把这个变量的地址&rdfds, &wtfds, &exfds
传递给select函数。这三个参数都是一个句柄的集合,第一个rdfds是用来保存这样的句柄的:当句柄的状态变成可读的时系统就会告诉select函
数返回,同理第二个wtfds是指有句柄状态变成可写的时系统就会告诉select函数返回,同理第三个参数exfds是特殊情况,即句柄上有特殊情况发
生时系统会告诉select函数返回。特殊情况比如对方通过一个socket句柄发来了紧急数据。如果我们程序里只想检测某个socket是否有数据可
读,我们可以这样:fd_set rdfds; /* 先申明一个 fd_set
集合来保存我们要检测的 socket句柄 */
struct timeval tv; /* 申明一个时间变量来保存时间 */
int ret; /* 保存返回值 */
FD_ZERO(&rdfds); /* 用select函数之前先把集合清零 */
FD_SET(socket, &rdfds); /* 把要检测的句柄socket加入到集合里 */
tv.tv_sec = 1;
tv.tv_usec = 500; /* 设置select等待的最大时间为1秒加500毫秒 */
ret = select(socket + 1, &rdfds, NULL, NULL, &tv); /*
检测我们上面设置到集合rdfds里的句柄是否有可读信息 */
if(ret < 0) perror("select");/* 这说明select函数出错 */
else if(ret == 0) printf("超时\n"); /*
说明在我们设定的时间值1秒加500毫秒的时间内,socket的状态没有发生变化 */
else { /* 说明等待时间还未到1秒加500毫秒,socket的状态发生了变化 */
printf("ret=%d\n", ret); /*
ret这个返回值记录了发生状态变化的句柄的数目,由于我们只监视了socket这一个句柄,所以这里一定ret=1,如果同时有多个句柄发生变化返回的
就是句柄的总和了 */
/*
这里我们就应该从socket这个句柄里读取数据了,因为select函数已经告诉我们这个句柄里有数据可读
*/
if(FD_ISSET(socket, &rdfds)) { /*
先判断一下socket这外被监视的句柄是否真的变成可读的了 */
/* 读取socket句柄里的数据 */
recv(...);
}
}

注意select函数的第一个参数,是所有加入集合的句柄值的最大那个值还要加1。比如我们创建了3个句柄:
int sa, sb, sc;
sa = socket(...); /* 分别创建3个句柄并连接到服务器上 */
connect(sa,...);
sb = socket(...);
connect(sb,...);
sc = socket(...);
connect(sc,...);

FD_SET(sa, &rdfds);/* 分别把3个句柄加入读监视集合里去 */
FD_SET(sb, &rdfds);
FD_SET(sc, &rdfds);

在使用select函数之前,一定要找到3个句柄中的最大值是哪个,我们一般定义一个变量来保存最大值,取得最大socket值如下:int
maxfd = 0;
if(sa > maxfd) maxfd = sa;
if(sb > maxfd) maxfd = sb;
if(sc > maxfd) maxfd = sc;

然后调用select函数:ret = select(maxfd + 1, &rdfds, NULL, NULL, &tv); /*
注意是最大值还要加1 */

同样的道理,如果我们要检测用户是否按了键盘进行输入,我们就应该把标准输入0这个句柄放到select里来检测,如下:
FD_ZERO(&rdfds);
FD_SET(0, &rdfds);
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = select(1, &rdfds, NULL, NULL, &tv); /* 注意是最大值还要加1 */
if(ret < 0) perror("select");/* 出错 */
else if(ret == 0) printf("超时\n"); /*
在我们设定的时间tv内,用户没有按键盘 */
else { /* 用户有按键盘,要读取用户的输入 */
scanf("%s", buf);
}

如何设置socket的Connect超时

1.首先将标志位设为Non-blocking模式,准备在非阻塞模式下调用connect函数
2.调用connect,正常情况下,因为TCP三次握手需要一些时间;而非阻塞调用只要不能立即完成就会返回错误,所以这里会返回EINPROGRESS,表示在建立连接但还没有完成。
3.在读套接口描述符集(fd_set rset)和写套接口描述符集(fd_set
wset)中将当前套接口置位(用FD_ZERO()、FD_SET()宏),并设置好超时时间(struct
timeval *timeout)
4.调用select( socket, &rset, &wset, NULL, timeout )
返回0表示connect超时
如果你设置的超时时间大于75秒就没有必要这样做了,因为内核中对connect有超时限制就是75秒。

网络编程中socket的分量我想大家都很清楚了,socket也就是套接口,在套接口编程中,提到超时的概念,我们一下子就能想到3个:发送超时,接收超时,以及select超时(注:
select函数并不是只用于套接口的,但是套接口编程中用的比较多),在connect到目标主机的时候,这个超时是不由我们来设置的。不过正常情况下这个超时都很长,并且connect又是一个阻塞方法,一个主机不能连接,等着connect返回还能忍受,你的程序要是要试图连接多个主机,恐怕遇到多个不能连接的主机的时候,会塞得你受不了的。我也废话少说,先说说我的方法,如果你觉得你已掌握这种方法,你就不用再看下去了,如果你还不了解,我愿意与你分享。本文是已在Linux下的程序为例子,不过拿到Windows中方法也是一样,无非是换几个函数名字罢了。
Linux中要给connect设置超时,应该是有两种方法的。一种是该系统的一些参数,这个方法我不讲,因为我讲不清楚:P,它也不是编程实现的。另外一种方法就是变相的实现connect的超时,我要讲的就是这个方法,原理上是这样的:
1.建立socket
2.将该socket设置为非阻塞模式
3.调用connect()
4.使用select()检查该socket描述符是否可写(注意,是可写)
5.根据select()返回的结果判断connect()结果
6.将socket设置为阻塞模式(如果你的程序不需要用阻塞模式的,这步就省了,不过一般情况下都是用阻塞模式的,这样也容易管理)
如果你对网络编程很熟悉的话,其实我一说出这个过程你就知道怎么写你的程序了,下面给出我写的一段程序,仅供参考。
/******************************
* Time out for connect()
* Write by Kerl W
******************************/
#include <sys/socket.h>
#include <sys/types.h>
#define TIME_OUT_TIME 20 //connect超时时间20秒
int main(int argc , char **argv)
{
………………
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0) exit(1);
struct sockaddr_in serv_addr;
………//以服务器地址填充结构serv_addr
int error=-1, len;
len = sizeof(int);
timeval tm;
fd_set set;
unsigned long ul = 1;
ioctl(sockfd, FIONBIO, &ul); //设置为非阻塞模式
bool ret = false;
if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) ==
-1)
{
tm.tv_set = TIME_OUT_TIME;
tm.tv_uset = 0;
FD_ZERO(&set);
FD_SET(sockfd, &set);
if( select(sockfd+1, NULL, &set, NULL, &tm) > 0)
{
getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len);
if(error == 0) ret = true;
else ret = false;
} else ret = false;
}
else ret = true;
ul = 0;
ioctl(sockfd, FIONBIO, &ul); //设置为阻塞模式
if(!ret)
{
close( sockfd );
fprintf(stderr , "Cannot Connect the server!n");
return;
}
fprintf( stderr , "Connected!n");
//下面还可以进行发包收包操作
……………
}

以上代码片段,仅供参考,也是为初学者提供一些提示,主要用到的几个函数,select,
ioctl,
getsockopt都可以找到相关资料,具体用法我这里就不赘述了,你只需要在linux中轻轻的敲一个man
<函数名>就能够看到它的用法。
此外我需要说明的几点是,虽然我们用ioctl把套接口设置为非阻塞模式,不过select本身是阻塞的,阻塞的时间就是其超时的时间由调用select
的时候的最后一个参数timeval类型的变量指针指向的timeval结构变量来决定的,timeval结构由一个表示秒数的和一个表示微秒数(long类型)的成员组成,一般我们设置了秒数就行了,把微妙数设为0(注:1秒等于100万微秒)。而select函数另一个值得一提的参数就是上面我们用到的fd_set类型的变量指针。调用之前,这个变量里面存了要用select来检查的描述符,调用之后,针对上面的程序这里面是可写的描述符,我们可以用宏FD_ISSET来检查某个描述符是否在其中。由于我这里只有一个套接口描述符,我就没有使用FD_ISSET宏来检查调用select之后这个sockfd是否在set里面,其实是需要加上这个判断的。不过我用了getsockopt来检查,这样才可以判断出这个套接口是否是真的连接上了,因为我们只是变相的用select来检查它是否连接上了,实际上select检查的是它是否可写,而对于可写,是针对以下三种条件任一条件满足时都表示可写的:
1)套接口发送缓冲区中的可用控件字节数大于等于套接口发送缓冲区低潮限度的当前值,且或者i)套接口已连接,或者ii)套接口不要求连接(UDP方式的)
2)连接的写这一半关闭。
3)有一个套接口错误待处理。
这样,我们就需要用getsockopt函数来获取套接口目前的一些信息来判断是否真的是连接上了,没有连接上的时候还能给出发生了什么错误,当然我程序中并没有标出那么多状态,只是简单的表示可连接/不可连接。
下面我来谈谈对这个程序测试的结果。我针对3种情形做了测试:
1. 目标机器网络正常的情况
可以连接到目标主机,并能成功以阻塞方式进行发包收包作业。
2. 目标机器网络断开的情况
在等待设置的超时时间(上面的程序中为20秒)后,显示目标主机不能连接。
3. 程序运行前断开目标机器网络,超时时间内,恢复目标机器的网络
在恢复目标主机网络连接之前,程序一只等待,恢复目标主机后,程序显示连接目标主机成功,并能成功以阻塞方式进行发包收包作业。
以上各种情况的测试结果表明,这种设置connect超时的方法是完全可行的。我自己是把这种设置了超时的connect封装到了自己的类库,用在一套监控系统中,到目前为止,运行还算正常。这种编程实现的connect超时比起修改系统参数的那种方法的有点就在于它只用于你的程序之中而不影响系统。

linux中errno使用

当linux中的C api函数发生异常时,一般会将errno变量(需include
errno.h)赋一个整数值,不同的值表示不同的含义,可以通过查看该值推测出错的原因,在实际编程中用这一招解决了不少原本看来莫名其妙的问题。但是errno是一个数字,代表的具体含义还要到errno.h中去阅读宏定义,而每次查阅是一件很繁琐的事情。有下面几种方法可以方便的得到错误信息
(1)void perror(const char *s)
函数说明
perror ( )用来将上一个函数发生错误的原因输出到标准错误(stderr),参数s
所指的字符串会先打印出,后面再加上错误原因 字符串。此错误原因依照全局变量
errno 的值来决定要输出的字符串。
(2) char *strerror(int errno)
将错误代码转换为字符串错误信息,可以将该字符串和其它的信息组合输出到用户界面例如
fprintf(stderr,"error in CreateProcess %s, Process ID %d
",strerror(errno),processID)
注:假设processID是一个已经获取了的整形ID
(3)printf("%m", errno);
另外不是所有的地方发生错误的时候都可以通过error获取错误代码,例如下面的代码段

#include"stdio.h"
#include "stdlib.h"
#include "errno.h"
#include "netdb.h"
#include "sys/types.h"
#include "netinet/in.h"
int main (int argc, char *argv[])
{
struct hostent *h;
if (argc != 2)
{
fprintf (stderr ,"usage: getip address\n");
exit(1);
}

if((h=gethostbyname(argv[1])) == NULL)
{

herror("gethostbyname");
exit(1);
}

printf("Host name : %s\n", h->h_name);
printf("IP Address : %s\n", inet_ntoa (*((struct in_addr *)h->h_addr)));
return 0;
}


通过上面的代码可以看到:使用gethostbyname()函数,你不能使用perror()来输出错误信息(因为错误代码存储在
h_errno 中而不是errno 中。所以,你需要调用herror()函数。
你简单的传给gethostbyname()
一个机器名("bbs.tsinghua.edu.cn"),然后就从返回的结构struct hostent
中得到了IP 等其他信息.程序中输出IP 地址的程序需要解释一下:h->h_addr
是一个char*,但是inet_ntoa()函数需要传递的是一个struct in_addr
结构。所以上面将h->h_addr 强制转换为struct
in_addr*,然后通过它得到了所有数据。

解决TCP-socket -掉线问题的总结(转)

直接用socket做的服务器和客户端,程序做的差不多了,实际使用时,发现经常"掉线",而程序不知道,找了许多解决办法,最后全都用上了,总结一下。

1:在连接时,设置他的avalie保活定时器.

Type
TCP_KeepAlive = record
OnOff: Cardinal;
KeepAliveTime: Cardinal;
KeepAliveInterval: Cardinal;
end;

procedure TFrm_Client.Sck_MainConnect(Sender: TObject;
Socket: TCustomWinSocket);
var val:TCP_KeepAlive;
Ret:DWord;
begin
inherited;
try
val.OnOff:=1;
val.KeepAliveTime:=1000 * 60 * 60 * 24; //24小时
val.KeepAliveInterval:=100;
Ret:=WSAIoctl(socket.SocketHandle, IOC_IN or IOC_VENDOR or 4,
@val, SizeOf(Val), nil, 0, @Ret, nil, nil)
finally
showInfo('已经连接到服务器.TCP_KeepAlive定时器'+intToStr(val.KeepAliveTime)+'结果:'+intToStr(Ret));
end;
end;

含义一目了然,不再多说。

2:在出错中检查10053之类错误,遇到就直接close,主动触发关闭事件,在关闭事件中触发自动重新连接的timer的自动重连:

procedure TFrm_Client.Sck_MainError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
Var nCode:Cardinal;
begin
inherited;
showInfo('||[Error]出错:'+intToStr(ErrorCode)+';自动重连:'+boolToStr(lAskForReConnect,
true));
nCode:=ErrorCode; //GetLastError;
ErrorCode:=0;
//如果出错,关闭,触发断开事件
if (nCode=EConnAborted) //10053 EConnAborted WSAEConnAborted
or (nCode=ENetDown) //10050 ENetDown
or (nCode=ETimedOut) //10060
or (nCode=EConnRefused) //10061
or (nCode=EHostUnReach) //10065
then begin
if lAskForReConnect and (not lInReConnecting) then
Timer_ReConnect.enabled:=true; //ReConnectServer;
if not lInReConnecting then begin
sck_Main.active:=false;
sck_Main.close; //ReConnectServer and (not sck_Main.active)
end;
showInfo('
连接状态:'+boolToStr(sck_Main.active,true)+';重连设置:'+boolToStr(lAskForReConnect,true)+';重连状态:'+boolToStr(timer_ReConnect.enabled,true));
end;
end;
//断开连接,断开时自动尝试再次连接,连接不上才断开
procedure TFrm_Client.Sck_MainDisconnect(Sender: TObject; Socket:
TCustomWinSocket);
begin
inherited;
if (not lAskForReConnect) or (lInReConnecting) then exit;
Timer_ReConnect.enabled:=true; //ReConnectServer;
end;
//重新连接
Function TFrm_Client.ReConnectServer:Boolean;
const nMax=6;
var Qry:TAdoQuery; L,L2:Boolean; i:Integer; s:String;
begin
Result:=False; i:=1; if not lAskForReConnect then exit;
L:=frm_MDI.ASysConfig.lAutoLogon;
qry:=nil;
with sck_Main do
try
if not lInCreatting then //or (not lLoginOK)
try
if not lAskForReConnect then exit;
sck_Main.Socket.Disconnect(sck_Main.Socket.Handle);
sck_Main.Close;
if L then begin
showInfo('断线,开始尝试自动重新连接服务器,最大重试次数['+intToStr(nMax)+']...');
&nsp; i:=1; //尝试3次重新连接
while (not sck_Main.active) and (i<=nMax) do
try
if not lAskForReConnect then break;
showInfo('
*尝试自动重新连接['+intToStr(i)+'/'+intToStr(nMax)+']...');
sck_Main.Open;
delay(2000);
L2:= sck_Main.active;
//connectToServer(sck_Main, txt_svrIP.text,
strToIntDef(txt_SvrPort.text,65180));
if not L2 then delay(1000); //sck_Main.active
inc(i);
except
on x:Exception do ;
end;
end;
//
except
on x:exception do ;
end;
finally
lLoginOK:=sck_Main.Active;
if not lLoginOK then begin
showInfo('已经断开服务器的连接,正在尝试重新连接');
lbl_Move.caption:='已经断开连接,正在尝试重新连接';
end;
Result:=lLoginOK;
s:='失败';
if lLoginOK then
Try
s:='[第'+intToStr(i)+'次重试成功]';
qry:=tAdoQuery.create(self);
qry.connection:=dmain.conn_Main;
clsAskForNewMessages(sck_Main.Socket, qry);
finally
if assigned(qry) then qry.free;
End;
if L then showInfo('断线重新连接结果:'+s);
end;
End;

procedure TFrm_Client.Timer_ReconnectTimer(Sender: TObject);
var msg:_msgIdle;
begin
inherited;
Try
//已连接了或用户不要求自动重连,则退出
showInfo('[##Timer_ReconnectTimer]断线自动重连。连接状态:'+boolToStr(sck_Main.active,true)+';重连设置:'+boolToStr(lAskForReConnect,true)+';重连状态:'+boolToStr(timer_ReConnect.enabled,true));
if (sck_Main.active) or (not lAskForReConnect) then exit;
//
lInReConnecting:=True; //处于连接中
timer_ReConnect.enabled:=False;
timer_ReConnect.enabled:=(not ReConnectServer) and
lAskForReConnect; //连上就停止
//
finally
lInReConnecting:=False;
end;
end;

3:服务器上。信息发送都用一个sendMessage方法,在他里边给socket加上错误处理,也时遇到10053错误直接就直接认为已经断开了。

//发送聊天信息
function sendMessage(socket:TCustomWinSocket; nType:Integer;
pMessage:Pointer):boolean;
const sFile='d:\aa.txt';
var tp:_msgHead; buf, pMsg, p:pByte; f,m,hBuf:THandle;
pOldErrorEvent:TSocketErrorEvent;
s:String; n,i,nLen,nMsgLen:integer;
begin
result:=false; buf:=nil; m:=0;
if lGlobalTerminate then exit;
//
try
pOldErrorEvent:=nil;
if assigned(pSocketErrProcedure) then begin
pOldErrorEvent:=socket.OnErrorEvent;
socket.OnErrorEvent:=pSocketErrProcedure;
end;
try
if not socket.Connected then raise
exception.Create('连接未打开或不存在');
//
tp.msgType:=nType;
nMsgLen:=getMessageTypeLen(nType);
if nMsgLen<0 then exit;
tp.nBagSize:=sizeof(tp)+nMsgLen;
tp.Version.dwMajorVersion:=frm_MDI.Version.dwMajorVersion; //1
tp.Version.dwMinorVersion:=frm_MDI.Version.dwMinorVersion; //0
//
nLen:=nMsgLen+sizeOf(tp)+0;
//分配内存区、复制头 globalAlloc(gmem_MoveAble, n+sizeOf(tp));
hBuf:=globalAlloc(GMEM_MOVEABLE + GMem_Share, nLen);
buf:=globalLock(hBuf); //getMem(buf, nLen);
fillChar( buf^, nLen, #0);
copyMemory(buf, @tp, sizeOf(tp)); //strCopy(buf, @tp);
//复制内容到全部内存区
if (nMsgLen<>0) and (pMessage<>nil) then begin
n:=integer(buf)+sizeOf(tp);
p:=ptr(n);
copyMemory(p, pMessage, nMsgLen); //strLCopy(p, pMessage,
nMsgLen); //copyMemor(p, pMessage, nMsgLen);
end;
//发送,重试n次,最多150ms
n:=-1; i:=1;
while (n=-1) and (i<=5) do begin
if lGlobalTerminate or (not socket.Connected) then break;
n:=socket.SendBuf(buf^, nLen);
if n=-1 then delay(10*i); //socket没有空间,则等待后重发
inc(i);
end;
//
result:=lGlobalTerminate or (n>-1);
except
on x:exception do begin
s:='[sendMessage]发送信息出错!Type='+intToStr(nType)+#13+#10+'
'+x.Message;
//if assigned(buf) then freeMem(buf);
insShowInfo(s);
raise eSocketError.Create(s);
end;
end;
finally
if assigned(pOldErrorEvent) then socket.OnErrorEvent:=pOldErrorEvent;
if assigned(buf) then begin
globalUnlock(hBuf);
globalFree(hBuf);
end;
end;
end;
//服务器端初始化时:

pSocketErrProcedure:=defaultSocketErrProcedure;

//socket出错的处理
procedure TFrm_Service.defaultSocketErrProcedure(Sender: TObject; Socket:
TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
var nCode:Integer;
begin
inherited; nCode:=errorCode;
//若出错,关闭
if nCode=10053 then begin
socket.Close;
raise exception.create('客户端已经断开连接了!');
end;
end;

4:心跳包,可能这个最有效,心跳包的意思,就是像心跳一样,每隔多长事件跳一次,跳自然会触发错误了。

//保持连接,心跳包
procedure TFrm_Client.Timer_KeepConnectTimer(Sender: TObject);
var msg:_msgIdle; H:TSocket; n:Integer; L:Boolean;
begin
inherited;
if (not lLoginOK) or (lInReConnecting) then exit;
L:=False;
try
if lGlobalTerminate then exit;
Timer_KeepConnect.enabled:=false;
//
//fillChar(msg.sComment,length(msg.sComment), #0);
msg.Version.dwMajorVersion:=frm_MDI.Version.dwMajorVersion;
msg.Version.dwMinorVersion:=frm_MDI.Version.dwMinorVersion;
msg.nTickCount:=0; //GetTickCount;
msg.nHandle:=0; //Socket.Handle;
msg.sComment:='你好!有空常联系!'; //sComment;
if not sendMessage(sck_Main.Socket, msgTypeIdle, @msg) then ;
//
//sendIdleMsg(sck_Main.socket);
{n:=timer_KeepConnect.interval;
H:=sck_Main.Socket.SocketHandle;
waitForData(n-300); }
L:=True;
finally
Timer_KeepConnect.enabled:=true;
showInfo('发送联系服务器消息IDLE'+intToStr(Timer_KeepConnect.interval)+',结果:'+boolToStr(L,true)+'...');
end;
end;

2009年6月9日星期二

美税率和物价比较

中国税率和国外税率的对比
  中国的个人所得税税率大大高于周边地区和主要发达国家(香港是2%-15%,新加坡是2%-28%,马来西亚是1%-29%,加拿大是17%-29%,日本是10%-37%,美国是15%-33%)。很多老百姓以为中国个人所得税是10%左右。大家被新闻说得西方国家个税才高。我要告诉大家的是,中国最高个人所得税率是45%,世界上仅仅几个国家才有这么高,美国最高个人所得税率33%。   
  我的一个朋友月薪15000,七扣八扣拿到手才11600,个人所得税20%;另外一个朋友18000,七扣八扣拿到手才13500,个人所得税2800左右,你说这还存什么钱?还号称工资高呢。   
  很多人连中国的个人所得税表都没有见过,让你看了吓一跳,我列在这里吧:级数全月应纳税所得额税率(%)
  超过2000元至5000元的部分15   
  超过5000元至20000元的部分20   
  超过20000元至40000元的部分25   
  超过40000元至60000元的部分30   
  超过60000元至80000元的部分35   
  超过80000元至100000元的部分40   
  超过100000元的部分45   
  在美国,为了防止你失业,投资失败等时候多交了税,每年年底你自己把退税证寄过去就可以,在网站直接可以办理。比如,你这一年失业了两个月,退两个月个人所得税。   
  美国你交了个税后,美国联邦政府每年会给你寄一个表,如果你交满个税信用40点,文件上会写得很清楚,59岁后你每个月能从国家领1000多美元一个月,如果这个时候你残废,你老婆和小孩分别可以每个月领取700美元。我当时在美国仅仅工作两年,缴税信用已经有20余点。这真的看起来很舒服。你的投入有回报。   
  2.养老   
  大家每个月工资会被扣一笔美其名曰的养老金,很多外来在深圳打工一族,没有深圳户口的都会被扣,这是国家强制的。同时你的公司也会帮你交一部分钱,公司帮你交的这笔钱以前有30%左右进入个人账户,70%左右直接被国家政府拿过去,这笔钱交社会统筹金。就是用你的钱养现在的老人。以前的养老,公司交的部分还有部分进入个人账户,现在是全部不进入个人账户啊!!!   
  在深圳,如果你交满15年,以后你可以拿到养老金。但是如果中途断了,换工作断了,你又拿不到钱了。如果你工资超过1万,你每个月被扣养老金好几大百的,公司也被扣好几大百的,到时候,就算你能领养老金,也和你交的这些差不多。又不是公务员或者行政机关单位,你能拿多少?   
  不妨把这个福利看成是公务员或事业机关单位的福利吧,对于其他打工的,这个真的可看成是另外一个税种,对企业和个人相当于多交了一份税吧。   
  国家有权的单位都拿着社保去投资,去亏空;所以越交越多,老百姓和公司压力越来越大。大家去看看Google搜索"挪用社保"的连接:不多说了,说多了很多人连这个简单的数学都看不懂了。很多人连这些简单的政策都搞晕了头。   
  我真的把社保当成自己交的另外一种税,我不认为我以后能拿到养老钱。   
  3.房子   
  这里可以写一大篇文章,我只例举几个事实。我的一个朋友在美国LasVegas买的房子22万美元,合160万人民币,大家看过电影吧,美国的房子都是别墅啊!同样的别墅在中国广州,北京,深圳,那个不是一千万以上啊。加州的房子大部分都是20万美元到60万美元之间!但是美国其他80%的省份都是5万美元到15万美元买别墅啊,买的是永久地产啊。美国交微薄的物业税,但是你交物业税可以抵消个人所得税,所以你根本没有感觉到巨大的压力。   
  中国买房交1.5%到3%的契税!   
  中国很多土地,土地成本就达到了6000每平米!中国物业管理费,这些权力勾结部门想出的办法,我朋友的房子70万买的,70年物业管理费要35万,这是50%的税!美国没有这个税,因为你交了个人所得税,社区每天早晨有车打扫卫生!   
  中国大城市的套间,那套不是80万到100多万,美国LosAngeles的套间(apartment)也只有不到10万美元的价钱,永久私有物业!   
  4.失业保险   
  这几乎是世界上最好笑和最令人痛心的保险之一,如果你工资超过1万元,每个月你交的钱和公司为你交的失业保险的钱加起来都300多了,就算你失业了,你跑各个部门为了拿到失业金,跑断了腿,最后能拿到400多一个月,能拿半年。这也算福利?我朋友这个工作保持了4年了,失业保险交了多少了?为何名字这么好听?为何不看成是另外一个税种?   
  美国也是只能拿半年,但是每个月仅仅交10多到20美元,拿失业金1000多美元一个月,拿半年后国家帮你找工作。但是1000除以20美元比率是多少,400除300比率又是多少?   
  5.教育   
  有了小孩,择校费,建校费都要好几万的,县城里的都要好几千了。这就是教育局的主意啊!简直不给老百姓家庭活路啊。大家要知道,美国是大学才有费用,小学,初中,高中都没有费用。   
  大学每年的费用1000多美元左右,已经超过了90%的国家,英国早几年的大学费用也才1000多英镑啊,只是这几年又涨了点。   
  6.汽车   
  在美国一辆1万美元的汽车(美国有很多电视汽车广告,首付2999,月299两年),中国要卖3万美元。老百姓永远都没有去想这后面的原因,因为一辆车进入海关关税就要200%,2万美元。当然关税在降,可还是不少。中国的电子产品增值税都要17%!大家去dell的网站买电脑,上面写着,中国用户增值税要17%,这在世界上实在是少见。   
  中国考驾照3000元人民币算少了,每次去考驾照必须交给考官大约500人民币左右吧(有关部门肯定不承认,可是这是所有拿驾照人说的啊,有关部门的口吻肯定会是:没有相关证据证明考官拿了钱。每个人都知道的事实可有关部门就是不知道);美国考驾照12美元;   
  中国办理汽车牌照上海3万人民币,美国加州洛城地区堵车堵得要命,办理牌照100美元以下!每个家庭可以办理几个牌照!   
  7.汽油   
  美国汽油现在2.3美圆一加仑(3.78升),美超级无铅汽油价格相当于4.86元人民币。而目前,北京市场上97号汽油的销售价格为5.42元人民币。而美国超级无铅汽油的含硫含铅等杂质符合国际标准,而我国国家标准对喊硫量的要求是国际一般标准20倍。可见,我国汽油品质明显低于国际水平,价格却明显高于美国。   
  美国的汽油零售价格的30%上缴燃油税,如果扣除燃油税,则价格更大大低于中国汽油价格。当然,美国燃油税征收的后果是,美国基本没有过路费,更无须养路费、车船使用税等...   
  美国实时汽油价格:ht tp://www. losangelesgasprices. com/;中国不给查,哈哈,在google都搜索不到。   
  很多人居然简单地说,我又没有私家车,汽油涨价和我无关。说话的,我且问你,你知道吗?汽油是一个国家的命脉。我这篇文章以事实和例子说话吧:以后产苹果的地方苹果只要1毛钱一斤,而大城市要10元一斤。以后汽车运费根本付不起,仅仅依靠铁老大,即为铁路运输。今年的卖枣农民惨烈把枣丢弃,到了县城不让卖,不给卖,不交税给工商局就没有摊位卖,地摊又不让摆。   
  春运的时候很多人在长沙汽车南站排队,可长沙去各个县城的车很少,根本没有跑高速的车,为什么?我后来仔细思考,才知道是因为高速路费,汽油费,工商局收费,根本无钱可赚;我每年都在长沙汽车南站为了回县城发愁,每每干脆租出租车回家。   
  政府好像在想推燃油税,现在汽油已经比美国贵很多了,还要加燃油税,这不可想象!这不可想象!   
  8.过路费   
  过路费堪称中国一绝,平均大约大约每一公里高速要0.4元!一套来回深圳到湖南要大约过路费150美元之巨!   
  目前,我国养路费轿车在1300元到1600元/年居多,个别省甚至达到2000多元。高速公路过路费价格在0.3到0.45元/公里居多,北京等建设成本高的地区在0.5元以上。如果以私家车每年出游行驶2000公里计算,每年用于高速公路的过路费在800元左右。我国除了北京、西藏、上海等少数省市,对一般公路都收取过路费,价格大多为10元/县。我国征收车船使用税为200元每年,这在美国是没有的。同时,我国驾驶员的违章罚款规模庞大,北京市以300万辆车创造了十几亿罚款,车均四五百元。如果把我国的养路费、车船税、过路费(保守估算小车应该在2500到2800元),计算入20000公里/年(油耗在7.5到9/百公里),相当于汽油价格每升再提高1.5到1.8元。   
  说话的,我且问你,国外就没有车违规罚款的吗?有!可我在美国开了2年车,仅仅有一次收到违规停车26美元的罚单。为何偏少,因为没有故意来抓你,没有靠这个来抓收入。你没有看到现在交警多少钱收入?考驾照的考官多少收入?   
  综合考虑,北京消费者的实际负担是人民币7到7.5元/升,应该具有一定的代表性。如果是外地消费者,可能由于城市小,行驶里程短,加上过路费更多一些,其平均到每升的花费更多。   
  你是深圳的车,进入广州居然要交10元入城费,外地的车进入上海也有入城费。这堪称最经典的中国特色。问题是每个地方政府都有权力收费啊。怎么玩啊?没法玩了。货运车交给工商局等费用后,基本没有利润了。我有些朋友原来跑中巴车,根本孝顺不起利益部门。   
  9.企业税   
  国内有个说法,如果按照正规纳税,任何企业都会破产或者做不起来。因为33%营业税,17%增值税,工商局,城管,税务局都来问你要收税等等。国内是公司每笔交易都缴税,不管你这笔交易是否营利;国外是等公司有营利再缴税。这么玩下去,大批企业都要倒闭的!
  10.医疗   
  医疗改革仅仅对公务员和事业机关有利!打工者没有真正享受到医疗改革。   
  11.中美物价比较
  仅仅用事实说话:美国希尔顿酒店49美元一晚,美国洛杉矶Holiday-lnn酒店49美元一晚,中国大城市都是1000人民币或以上;美国加州自助餐6美元一餐,晚上有海鲜的10美元;美国的电子,汽车等物品都比国内便宜;大家去ebay看看价钱吧。很多出国的人很多年没回国了,总是以为中国吃餐饭还是5元,8元的,总是拿中国的盒饭钱去比美国下馆子的钱。要省钱的话,美国一周买20美元,够吃一周,有一大壶牛奶,好几升,才2.99美元,每天三大杯,够喝一个星期;有牛肉,有水果和你一个星期要吃的蔬菜。   
  说到牛奶,我想说说,很多人可能不知道美国那才是真正的纯牛奶,还没喝,牛奶到了嘴边就有香味了,还会上瘾的。中国的牛奶大家去煮一下,就知道含多少水了,你会发现仅仅浮在上面一层是牛奶,这个令人惊叹的发现是我一个客户告诉我的。   
  为何国外物价便宜,因为各行各业中国税收实在是太高了

公司的四种死法 ---冯仑

不失其所者久,死而不亡者寿。
-----------老子
死 亡
按照一个企业正常的发展规律,在它从无到有的创业发展过程中,我们看到了很多的成功及其延续,在欧洲就有300多 年基业的企业。可毕竟绝大部分企业最终还是要走向死亡。这些企业的死亡,有一些是正常的,比如重组、并购、转卖,或是重新被家族分掉;有一些则属于意外死 亡,比如创始人突然出现生命威胁,或锒铛入狱,或遭遇其他打击而造成了企业死亡;当然还有因为不可抗力的偶然因素,比如说"9・11"后,一时间很多保险公司、航空公司纷纷死亡。所以在企业的生命历史上,研究企业的死亡,研究企业家对待死亡的态度,是一个角度很特殊的课题。
公司的四种死法
死亡是从一出生就开始面对和趋进的自然规律,但是人们从感情上不愿涉及而尽量避免这一话题,特别是创业者,更不想探讨企业的死亡。清醒的企业家是不应回避的。
从历史上看,企业有四种死亡的方式:
第一种,社会革命、制度变迁。比如1949年新中国成立后,1947年、1948年的国营企业和一些民族资本家的企业,经过1956年的社会主义改造,被政府赎买或者没收,变成了公有。所以社会革命会造成大量的企业的性质发生变化和死亡,这是第一种。
第二种,技术革命。当一种新技术进入快速发 展期,旧技术所能支持的一些企业就不复存在了。最典型的是,当汽车兴起的时候,制造马车的企业就死亡了;当我们现在用手机的时候,传呼机企业就死亡了;当 我们用玻璃杯、纸杯和其他瓷器、陶器时,搪瓷杯就被淘汰了,生产这些产品的企业也就死亡了。技术革命不断变化的过程会使非常多的企业死亡,这些死亡的企 业,往往起因于当事人(企业家)迟钝或不敏感,或对以往技术的偏执。最近几十年,技术革命发展非常快,每天由于技术发展导致死亡的企业数量非常大。特别是 在网络时代,比如现在搜索手段已经很发达了,那么原来对图书馆进行人工检索的行业就快消失了;比如技术进步让通信变得越来越迅速便捷,那么过去传统的通信 方式就没有了。技术变革本身导致企业的死亡将是经常性的和大规模的,较之第一种死亡,它不是很痛苦,而是在和平状态下不知不觉地死去。
第三种,不可抗力和不期而至的灾难。最典型的就是地震、海啸、战争,这些灾难会使很多企业破产,资不抵债。抵御这种灾难比较有效的是购买保险,预先做一些防范,避免死亡。最典型的是"9・11"之前世界贸易中心的运营商拉里・西尔弗斯坦的故事。世贸中心有120万平方米的写字楼,产权业主是纽新港务局,而承租者拉里・西尔弗斯坦拥有99年的运营权。他在"9・11"之前3个月买了一个抗恐怖主义保险,"9・11"后他获得了保险公司的赔付,于是这个不可抗力没有让他垮掉。如果他没有保险,那么他这个企业就垮掉无疑了。
第四种,商业竞争导致的死亡。按过去的研究看,每5~7年 为一个商业周期,每一个周期都是由危机导致萧条,然后复苏繁荣;再危机萧条,复苏繁荣,这样周而复始不断循环。导致危机的最主要原因是由于供需关系的矛 盾,造成了强制性的市场供求结构的调整,以及强制性的技术和固定资产更新。比如很多牛奶卖不出去,危机促使企业强制性减少奶牛场规模或制造其他奶制品,否 则公司就关门了。每轮商业周期循环都将会有一半以上的企业不复存在。
在人类的商业文明历史上,这四种方式足以让企业死亡,而每个民营企业预防、诊断然后避免死亡的方法各有不同。
社会革命我们是没有办法抗拒的,但现在社会革命并不会构成我们民营企业需要防范的方面。
应对技术革命,企业必须通过保持高度的警觉性、敏感性和技术竞争上的创新能力,来适应未来的市场和不断出现的新的产品。比如王安电脑都是大型机,可是市场上眼看小型PC机活过来,而且市场越来越好,但他拒绝变革,结果他的企业死亡了。如果他警觉敏感,能够及时转型,那就可以避免技术革命带来的死亡危机。
应对自然灾害,做一些预防是有必要的,但通常是防不胜防的。比如说恐怖主义保险,全世界没几个人买,可拉里买了,具有一定偶然性,但是总体来说还是可以做点预防。比如说我们做房地产,买防止地震的保险就很必要。
应对商业竞争,唯一的办法就是降低负债,扩 大现金流量的弹性,保持公司竞争性和财务稳健。因为经济危机一来,主要表现为银根紧张、市场萎缩、销售收入减少。这样带来的实际上是一个现金周转的问题, 如果你保持足够的现金,能够灵活地应对市场的供求变化,减少你的负债,一般来说就能活下来。目前,技术革命、信息革命和全球化以后带来的一个现象是,二战 以后全球性的、大的经济危机目前没有出现过。尽管局部东南亚经济危机出现过,但还不是以商业周期波动。经济学家一直在讨论:现在商业周期的波动还存在不存 在?早期经典的周期理论是强调信息不对称导致供求的矛盾加剧,最后导致强制性的危机和技术革命。现在有一种理论认为,信息在微观上已经很对称了,由于信息 技术的发展逐渐让信息对称,供求矛盾实际已经很难积聚到总爆发,现在就不大会出现全局性的商业周期波动。但即使看不到危机,我们还是要注意,市场波动、商 业竞争带来的危机仍然存在。表现的方式和程度可能有所不同,可能不是病来如山倒、山崩地裂,而是局部的,比如说家电业、房地产行业的波动和周期。应对商业 周期波动,最好的方法就是保持足够的现金流,减少负债,使你的产品能够应对市场的快速变化,这是唯一的存活之道。

《金融危机下的中国银行业》――马蔚华

《金融危机下的中国银行业》 纪要
马蔚华 2009.6.5 ・深圳综合开发研究院
一 中国银行业的 30 年成就
1、 体制内的改革:从中国人民银行职能转变,中、农、工、建、交五大国有银行的开业,
2、 体制外的改革:以招商银行为例

(1)"比别人早一点,快一点,好一点",比同业想得更前一些,先走一步。2个经典案例:一是"一卡通",其卡均存款是其他银行卡的 2.8 倍;二是"网上银行",目前业务替代率是 70%,突破了物理网点有限的限制,培养了特定的客户群体。在信用卡业务上,国内最早做,且起初婉拒了花旗的合作建议,第 4 年已实现盈利,目前信用卡的业务重点已不再是发卡量,转向利润,目前 40%来自于透支消费的利息收入。
(2)招行的一些理念:
i 与外资行在经营理念上依然有差距;
ii 把握合理的规模扩张速度,风险可控,不超出管理能力;
iii 效益增长比规模增长更重要;
iv 理性对待市场,理性对待同业,理性对待自己;
v 识变,遵循价值导向,2009 年分支机构的考核不再用传统的账面利润进行考核,转向包含资本消耗的经济利润来考核,从而引导业务重点转向成本低的中间业务和零售中小客户群
vi 银行是本土的,海外整合经验只有 30%是成功的 (编注:可参考汇丰式并购一文)
vii 企业文化是核心竞争力;

二、金融危机的影响
1、 中国银行业因"涉水较浅",所持有的有毒资产微不足道,直接影响不大,而非"水性好"。
2、 目前美国人的消费习惯发生变化。在危机之前,每个家庭的负债和资产比是 133%,而近期发现他们的储蓄率已经上升到 5%左右。
3、出口的急剧下滑影响实体经济,传导至微观上的企业、大宗商品、就业等环节。有效信贷需求减少;息差收窄;利息支出成本上升;中间业务发展乏力。

金融危机对银行的机遇请参见本文后附的《马蔚华:危机中的中国银行业十大机遇》一文。

对中国经济复苏和长期看好的一些理由与预期:
1、 后工业时代,由劳动力密集型转向资本密集型;
2、 城市化进程,当前城市化率 30%,预期未来几十年后达到 70%
3、 消费革命,消费理念的变化,如年轻一代的透支消费行为;
4、 区域经济不平衡下,地方政府组织发展经济的动机与能力

中国银行业面临的挑战:
1、 金融脱媒,直接资本市场发展潜力巨大,债券融资、IPO 融资对传统信贷融资的冲击;
2、 支付平台的兴起,第三方支付如阿里巴巴的支付宝;
3、 利率市场化考验定价能力;
4、 信息化改造(智能电网等信息化发展趋势)
5、 国际化,上半年跨境收购大幅增加,客户已经走出去。

三、提问环节
Q:收购永隆银行,是否价格过高,以及当前业务开展情况
M:收购永隆的意义:之前在香港无机构,而目前招行 40%的客户位于华南地区,且香港客
户对内地也有需求;
收购的价格:从近些年交易来看,能够完全收购香港银行的机会很少,且 PB 基本在 3
左右,如果能够等价格大幅下跌后,也不见得原股东一定会卖出。
对永隆的经营计划:1 年初显整合成效,3 年变样(融入招行体系) 5年获得成功;目前 09 年 Q1 已实现盈利,并好于预期;
对永隆的业务支持: "港粤一线通"开发产品服务,永隆卡可在内地招行所有网点取现,信用卡等同于招行信用卡,在永隆的资产可以担保境内的招行贷款,在境内的招行的资产也可以担保在香港的贷款,等等

Q :商业银行在本轮信贷扩张大潮中远远落后于国有银行,如何应对?
M:天然上没有批发业务的优势,继续强调差异化,这样的外部压力可以促进内部的变化,调整业务结构,把握时机,继续保持中小企业服务和零售金融业务上的先机。

Q:国际化的下一步计划?
M:整合的能力,目前的关键在于国际化的管理人才,管理制度和管理能力。

Q:银监会放开商业银行新设网点的审批,招行网点的扩展是否会加速
M:不会改变之前计划,新开数量控制在 100 以内,管理能力决定扩张速度。

Q:宁波银行、杭州银行以及平安银行等同业的竞争压力?
M:招行的几个优势:1 品牌优势,服务水平,有"先入为主"的优势;2 业务整体的优势,不止是简单的存款业务,有各种理财产品、信用卡、贷款、对公业务,业务越多,忠诚度越高,迁移成本越高,不会因为利息的一些优惠轻易离开;3. 文化决定服务优势

附:马蔚华:危机中的中国银行业十大机遇

辩证看待全球金融危机对我国商业银行的影响
马蔚华:危机总是与机遇相伴随,只要牢牢抓住"危"中之"机""危机"就会成为转机

■招商银行行长 马蔚华博士
"目前,金融危机对于实体经济的影响,已经越来越多地反作用于银行,国内银行正面临着不断加大的风险、经营与盈利压力。但同时也蕴含着不少前所未有的机遇"
我们正在经历的这场全球金融危机,其波及范围之广、影响程度之深、冲击强度之大,为上世纪 30 年代以来所罕见。在过去两年,由美国次贷危机引发的金融危机愈演愈烈,迅速穿透资本市场、货币市场和信贷市场,从局部发展到全球,从金融领域扩散到实体经济领域,给世界各国经济发展和人民生活带来严重影响。
目前,全球金融危机进一步升级为全球经济危机的趋势日益凸现。这对我国持续多年的投资和出口拉动型的经济增长模式带来了巨大冲击。自去年下半年以来,我国经济增速大幅下滑,工业生产显著放缓,企业经营更加困难,财政收入增幅回落,资产市场持续低迷。全球金融危机对我国经济的影响已经从出口行业传导至与出口相关的原材料、加工、从沿海发达地区扩散至内地边远地区,从中小企业蔓延至国有大中型企
业,中国经济正面临进入新世纪以来最为艰难的时刻。
由于国内银行业参与国际市场的程度还不深,加之近年来商业银行与资本市场实行隔以及监管当局审慎监管政策的有效实施,因此此次金融危机对我国银行业的直接冲击并不大,国内银行受到的直接损失是有限的。但是,金融是经济的反映,经济出了问题,金融肯定要出问题。目前,金融危机对于实体经济的影响,已经越来越多地反作用于银行,国内银行正面临着不断加大的风险、经营与盈利压力。从业务拓展看,在经济下行、市场趋冷、信心受挫的情况下,银行作为社会融资中介、支付中介和财富管理中介的职能发挥无论是公司信贷、个人信贷和贸易融资等一般性贷款业务,还是公司负债、同业负债等对公负债业务;无论是 POS 消费、代理服务、托管受托、结算清算等支付类业务,还是 QDII、外汇投资、结构性产品等财富管理业务,市场拓展都更为艰难;从风险在全球金融危机和国内经济下行的叠加作用下,银行面临的风险不断呈现出系统性、连锁性和突发性的特征与趋势,包括行业风险、信用风险、利率汇率风险、流动性风险、操作风险、合规风险和声誉风险等在内的各种风险相互交织、相互作用,银行稍有不慎,就有可能陷入深渊;从盈利情况看,在有效信贷需求趋于减弱、存贷利差持续缩窄、利息支出成本逐渐上升、中间业务增长乏力、风险资产逐步增多、拨备支出显著增大等因今年乃至今后一段时期银行净利润增速将明显放缓,过去那种超常增长的局面将难以再现。
然而,危机中也蕴含着机遇的因素,正如英国作家布瑞杰所说,"中文的'危机'分为两个字,一个意味着危险,另一个意味着机会。"确实如此,危机总是与机遇相伴随,危中有机,只要善于发现,善于把握,牢牢抓住"危"中之"机""危机"就会成为"转机"。从事物发展规律看,任何事物都是矛盾统一体,而矛盾双方的力量会随着形势变化而此消彼长,主次地位也会出现逆转,由此发生质的转变。所谓"祸兮福所倚,福兮祸所伏"讲的就是这个道理;从经济周期理论看,经济总是按照繁荣、衰退、萧条、复苏四个阶段周而复始的运行,萧条之后便是新一轮的复苏,因此著名经济学家熊彼特就曾说过"为危机而担忧是大可不必的,对市场经济来说,萧条是一服很好的清醒剂";从历史实践经众多企业就是因为抓住了"危"
中之"机"而实现了跨越式的发展,如大萧条后 IBM的全球崛起,上世纪 70 年代石油危机后日本汽车业的辉煌,亚洲金融危机后三星电子的腾飞,等等。总之,危机往往会动摇旧的规则,促成变革,从而成为重大历史事件的转折点。
当前形势尽管对我国商业银行的经营构成了严峻挑战,但同时也蕴含着不少前所未有的机遇。这主要体现在以下方面:
第 1 ,国家扩大内需政策的强力实施
为保证我国经济平稳较快增长,中央和地方政府在基础设施、民生工程、生态建设和灾后重建等领域投入巨资,并出台一系列措施加快推进农村城镇化、农业工业化进程。这将极大刺激国内投资需求和消费需求的扩张,四万亿资金的投入提供了相应的信贷需求,特别是为银行适时介入和拓展政府融资平台、项目融资、中长期贷款、银团贷款等业务提供了新机会。
第 2 ,市场主体结构的重新洗牌
在金融危机的冲击下,优胜劣汰的市场机制将使市场结构发生深刻变化,企业间新一轮的并购、重组浪潮将再次掀起。最新一期汤森路透亚太区并购季报显示,全球其他地区并购活动在 2008 年均出现回落,交易额下降 29.6%至 2.9 万亿美元,而同期中国并购活动仍保持强势并飙升至历史新高的 1596 亿美元交易额,较 2007 年跃升了 44%,预计 2009年这一趋势将得以延续。与此同时,行业兴衰更替的特征也将进一步凸现,包括生态环保、服务外包、电子商务、新材料新能源应用等一大批朝阳行业将迅速崛起。这既拓宽了银行并购贷款、财务顾问等业务的发展空间,也扩大了银行潜在的价值客户群。
第 3 ,企业调整转型的加快实施
为有效应对危机,企业纷纷转变经营模式、优化产品结构、加强自主创新、实施技术改造和升级转型,并且更加注重多产品、多客户、多渠道、多市场的营销策略。比如,在受金融危机冲击较为严重的珠三角地区,企业尤其是中小民营企业主动调整转型的步伐普遍加快,通过出口转内销、完善产品设计能力、加大科研投入等手段加速实现从生产型企业到市场型、创新型企业的转变,仅半年时间,东莞市已有 47 家来料加工企业转为了三资企业, 52 家企业积极进行自主品牌创建申报;而佛山市仅南海区一个区就已经有 200多家民营企业转型升级成功。另一方面,各级地方政府从资金、土地、税收等多方面为企业解决实际困难,减轻企业负担,优惠政策之多、扶持力度之大,为多年来所罕见。通过自身的升级转型以及政府的有力扶持,企业抵御金融危机的能力将得以明显增强。这减少了银行的经营风险,也有利于银行更好地拓展业务,特别是中长期贷款、股权融资、应收账款保理融资等融资业务。
第 4 ,居民资产配置的动态调整
随着收入水平的不断提升以及金融消费观念的更新,居民的理财需求和财富管理的需求日益增长,这种趋势并不会因金融危机而发生逆转。据不完全统计,去年国内银行理财产品发售规模超过 2.3 万亿元,是 2007 年发行额的大约 3 倍。而且,随着市场波动加剧,居民对自身资产池的结构调整更加关注,对资产配置动态调整的意愿更强。据目前 90%左右的银行认为股市波动对储蓄存款和同业存款的影响较大,这也充分体现了居民资产配置鲜明的动态转换特征。因此,只要银行不断丰富产品体系,主动适应客户需求变化,当前形势下财富管理业务和私人银行业务仍有很大的发展潜力。
第 5 ,同业竞争格局与策略的悄然变化
国外许多大的金融机构在此次金融风暴中受到程度不同的冲击或损害,从而使一些优质高端客户选择到中资银行开办业务,中资银行的声誉显著提高。在国内银行市场上不少同业实施了客户结构和业务结构调整策略,收缩或退出了某些业务与市场,进而为其他银行有选择性地介入腾出了相应的空间。另外,当前基金、证券、信托等非银行金融机构与商业银行抱团过冬的合作意识明显增强,这给银行更好地拓展同业业务和开展产品交叉销售带来了大好机会。
第 6 ,直接融资工具的快速发展
为了扩大社会投资和缓解企业资金压力,政府加大债券市场扩容力度,除积极鼓励企业发行企业债、公司债和中期票据等传统债券品种外,还积极推动可分离债券、浮动利息债券、中小企业短期融资券及集合债券等新型债务融资工具发展。据统计,2008 年全国包括公司债、企业债、短融和中期票据在内的信用债发行量达到 9433 亿元,是 2007 的1.72 倍,而今年的发行量有望达到 1.2 万亿至 1.3 万亿元。其中,交易所市场公司债的发行量可能达到 1500 亿元。除大力发展债券市场外,我国政府还将加快多层次资本市场建创业板等新型市场将加快推出。直接融资的快速发展在对银行融资业务构成严峻挑战的同时,也带动了银行债券发行承销、专项财务顾问等投资银行业务的发展,并且进一步拓展了银企合作的空间。
第 7 ,产业区域转移的加速推进
在成本增加和市场萎缩的双重挤压下,沿海地区劳动密集型、资源加工型产业逐步梯次迁往内地,更多生产要素也将在逐利性驱动下加速流向边际报酬率较高的中西部地区。据有关专家分析,东部沿海地区大规模产业转移估计 5 年左右完成,到 2010 年,仅广东、上海、浙江、福建 4 省市需要转出的产业产值将达到 14000 亿元左右。这无疑为银行提供配套金融服务、更好地拓展中西部市场提供了新的机会。
第 8 ,人民币债券投资的空间拓展
2008 年,伴随着货币政策基调从"从紧"到"适度宽松"的转变,债券市场在加息预期的减弱和宽裕资金的推动下走出了一波上涨行情,债券等固定收益产品平均年投资收益达 6.52%左右,大大超过股票类金融产品,市场出现债券投资热潮。今年,鉴于宏观经济形势更为严峻,可以预见货币政策将继续保持宽松,物价水平也将保持在低位运行,在持续降息将促进货币市场流动性不断释放,这为银行进一步优化人民币债券投资组合,扩大长久期债券投资机会,提高人民币债券投资组合收益率创造了新的环境。监管部门已经启动了上市商业银行在证券交易所参与债券交易的试点工作,并积极研究在银行间市场推出较高收益类债券,这将大幅提高我国债券市场的活跃度和交易量,有利于银行进一步完善债券投资渠道、提高投资收益。
第 9 ,跨境企业避险、套利的需求加大
在当前国际商品市场和金融市场走势扑朔迷离,特别是外汇和黄金市场加剧波动的情况下,企业跨境经营的风险不断加大,避险及套利的需求也随之增强。据权威调查显示,目前我国企业外汇避险需求总体在不断上升,有近 1/3 的企业希望银行能够提供更多的汇率风险管理产品。这有利于促进银行本外币、离在岸和境内外联动业务的深入开展,带动基于本外币汇差、利差的结构性避险增值类产品的创新发展。
第 10 ,吸收人才的良好时机
由于金融危机,国外金融机构大批裁员,许多海外优秀的金融人才纷纷选择回国就业。如在去年 12 月底广州举办的"中国留学人员广州科技交流会"上,共有来自 30 个国家和地区的近 1800 名留学人员报名参加。其中博士占 51%,首次超过报名总数的一半;过去比例较少的金融、法律人才占到 15%,其中有 80 多人曾供职于华尔街。国外优秀人才回流无疑进一步加剧了国内人才市场供给大于需求的买方市场特征,为银行物色、选聘各专业人才特别是高层次金融人才提供了难得的机会。总之,面对当前挑战与机遇并存、困难与希望同在的形势,只要我们坚定信心、危中求机,学会用辩证统一的思想方法去分析问题、研究方法、制定对策,坚持做到"既审慎又积极",国内银行业就一定能够顺利度过经济严冬,保持持续健康稳定发展。