分类目录归档:我的代码

原来Linux和Windows下的socket还是有那么多不同的

之前以为linux和windows下的socket都是符合posix标准的,在一个环境下能够正常使用在另外一个环境也没问题。但没想到两者还是有那么多不同。

1.最先发现的是在windows上需要调用那个WSAStartup进行初始化才能使用socket。

2.linux下关闭socket用close,而windows上用closesocket。

3.后来发现shutdown的参数名称不同,windows上用SD_BOTH,linux上是SHUT_RDWR。

4.在linux下如果不正常关闭socket会触发SIGPIPE异常,所以我使用signal( SIGPIPE, SIG_IGN );忽略之。

5.linux下可以使用read,write函数操作socket,也可以使用send,recv。windows上只能使用send,recv?(不考虑udp的sendfrom和recvfrom)

今天又发现一个很大的不同点了,造成了homeserver在短时间内生成了一个20GB的日志文件,用完了vps的硬盘空间。如果一个正在使用中的socket使用close来关闭之而不调用shutdown,则该socket还是处于连接中,只是在进程的文件描述符中移除了(right?)所以导致了使用那个socket的线程一直没有收到关闭信号,阻塞在socket的recv上无法被关闭。而在windows上调用closesocket就彻底地断开了连接了。

下面是网上提供的信息:
close—–关闭本进程的socket id,但链接还是开着的,用这个socket id的其它进程还能用这个链接,能读或写这个socket id
shutdown–则破坏了socket 链接,读的时候可能侦探到EOF结束符,写的时候可能会收到一个SIGPIPE信号,这个信号可能直到socket buffer被填充了才收到,shutdown还有一个关闭方式的参数,0 不能再读,1不能再写,2 读写都不能。

所以,以后关闭socket还是同时使用shutdown和close好。

 

补充一下(2010-06-13):
1、在linux下,shutdown会引起在recv和send中阻塞的线程返回-1。但是在windows下,除非closesocket,否则线程仍然阻塞。

2、windows的描述符是递增的,linux的描述符是重用的。也就是说你在linux下关闭了描述符0,然后打开一个文件,这个文件就是用了描述符0。

Windows上模仿Linux下的time程序:wintime

程序和源代码下载:upfiles/wintime.zip

Usage: wintime program
Time Recording Method:
real    The real time the program REALLY runs.
user    The time the program runs in USER mode.
sys     The time the program runs in KERNEL mode.

使用示例(亦可以把程序拖到wintime.exe运行):

E:>wintime amend < amend/amend9.in
80

real    0m0.734
user    0m0.750
sys     0m0.000

示例2:

E:>wintime a
1
2 2
3 3 3
4 4 4 4
5 5 5 5 5

real    0m0.015
user    0m0.015
sys     0m0.000

非主流C++ —— 一个没有分号的猜数字游戏代码

运行:

I have a number between 1 and 1000.
Can you guess my number?
Please type your first guess.
500
Too high. Try again.
425
Too low. Try again.
428
Too high. Try again.
427
Too high. Try again.
426
Excellent! You guessed the number!
Would you like to play again (y or n)?

大概6年前,用TC3 for Win写了一个猜数字游戏,貌似也是这个模样。现在为了做C++作业,也写了一个如此的游戏。不过,觉得主流的写法并不好玩,于是从一个主流代码开始不断“优化”,改头换面,最终一个非主流代码出现了——一个没有分号的猜数字游戏代码。

纯属是为了好玩,不适应的程序员或许看不懂这个代码,适应了就好了。经过这次实践,我得到一个如下的结论:
只要你有恒心,任何一个C++代码都可以写成一个没有分号的代码。

这样的写法不是为了装逼,而是一种纯粹的智力游戏,开发自己的创新思维,同时还能加深自己对C++原理的认识,何乐而不为?

而你的看法是怎么样的呢?

Linux下动态加载链接库

必须包含头文件 dlfcn.h。

使用到dlopen, dlclose, dlsym 3个主要函数,dlerror可以获取加载中遇到的错误的字符串。

下面给出部分代码,来自最新版homeserver:

	DBG("Loading plugin [%s]", name );
#ifdef __WIN32__
	p->handle = LoadLibrary( path );
	if( p->handle ){
		p->entry = (plugin_entry) GetProcAddress( p->handle,"plugin_entry");//
		p->cleanup = (plugin_entry) GetProcAddress( p->handle,"plugin_cleanup");//
	}
	if( !p->handle || p->entry==NULL ){
		DBG("# Loading plugin: %s failed: %d", path, GetLastError() );
#else
//linux
	p->handle = (int)dlopen( path, RTLD_LAZY );
	if( p->handle ){
		p->entry = (plugin_entry) dlsym( (void*)p->handle,"plugin_entry");//
		p->cleanup = (plugin_entry) dlsym( (void*)p->handle,"plugin_cleanup");//
	}
	if( !p->handle || p->entry==NULL ){
		DBG("# Loading plugin: %s failed: %s", path, dlerror() );
#endif

homeserver的源代码下载链接:

homeserver090930

Linux下使用readdir查找文件

在Windows上一直使用_findfirst查找文件,以为是标准库里的,可以在Linux下直接使用。今晚试了一下失败了。
Linux下使用readdir来扫描一个目录下的项目。首先,需要包含头文件dirent.h。然后定义下面搜索需要的结构。

DIR* dir_info; //目录指针
struct dirent* dir_entry; //目录项信息指针

//打开一个待扫描的目录
dir_info = opendir(“./plugins”);
if( dir_info ){
        //打开目录成功
while ( (dir_entry = readdir(dir_info)) != NULL)
{
             //忽略这两个特殊项目
             if(strcmp(dir_entry->d_name, “..”)==0 || strcmp(dir_entry->d_name, “.”)==0)
continue;
             //具体操作。。。
plugin_create( srv, dir_entry->d_name );
} // while
        //使用完毕,关闭目录指针。
        closedir(dir_info);
}

可惜,我没有找到有能够在windows和linux通用的文件扫描函数。所以只好用宏定义不同平台的处理方案。

#ifdef __WIN32__

#else

#endif