UCS-2与UTF8之间的选择(3)--windows与linux中各编码字符串的C/C++输出支持及方式比较
write by 九天雁翎(JTianLing) -- www.jtianling.com
讨论新闻组及文件
继续研究UTF8和UCS-2的选择,这里继续使用上一次提到的函数。
鉴于大家不一定能找到下载的地址,而源文件是允许自由散发的,我将代码打包,提供给大家下载,下载地址还是在讨论新闻组及文件中,名字为unicodeorg.rar,
另外,在wiki上看到了一个对UTF8的评价:
优点及缺点
关于字符串长度的一个注解:
总体来说,在Unicode字符串中不可能由码点数量决定显示它所需要的长度,或者显示字符串之后在文本缓冲区中光标应该放置的位置;组合字符、变宽字体、不可打印字符和从右至左的文字都是其归因。
所以尽管在UTF-8字符串中字元数量与码点数量的关系比UTF-32更为复杂,在实际中很少会遇到有不同的情形。
- 总体
- 优点
- UTF-8是ASCII的一个超集。因为一个纯ASCII字符串也是一个合法的UTF-8字符串,所以现存的ASCII文本不需要转换。为传统的扩展ASCII字符集设计的软件通常可以不经修改或很少修改就能与UTF-8一起使用。
- 使用标准的面向字节的排序例程对UTF-8排序将产生与基于Unicode代码点排序相同的结果。(尽管这只有有限的有用性,因为在任何特定语言或文化下都不太可能有仍可接受的文字排列顺序。)
- UTF-8和UTF-16都是可扩展标记语言文档的标准编码。所有其它编码都必须通过显式或文本声明来指定。[2]
- 任何面向字节的字符串搜索算法都可以用于UTF-8的数据(只要输入仅由完整的UTF-8字符组成)。但是,对于包含字符记数的正则表达式或其它结构必须小心。
- UTF-8字符串可以由一个简单的算法可靠地识别出来。就是,一个字符串在任何其它编码中表现为合法的UTF-8的可能性很低,并随字符串长度增 长而减小。举例说,字元值C0,C1,F5至FF从来没有出现。为了更好的可靠性,可以使用正则表达式来统计非法过长和替代值(可以查看W3 FAQ: Multilingual Forms上的验证UTF-8字符串的正则表达式)。
- 缺点
- 一份写得很差(并且与当前标准的版本不兼容)的UTF-8解析器可能会接受一些不同的伪UTF-8表示并将它们转换到相同的Unicode输出上。这为设计用于处理八位表示的校验例程提供了一种遗漏信息的方式。
--《UTF-8》
其中还有:
UTF-8编码的缺点
不利于正则表达式检索
正则表达式可以进行很多英文高级的模糊检索。例如,[a-h]表示a到h间所有字母。
同样GBK编码的中文也可以这样利用正则表达式,比如在只知道一个字的读音而不知道怎么写的情况下,也可用正则表达式检索,因为GBK编码是按读音排序的。只是UTF-8不是按读音排序的,所以会对正则表达式检索造成不利影响。但是这种使用方式并未考虑中文中的破音字,因此影响不大。Unicode是按部首排序的,因此在只知道一个字的部首而不知道如何发音的情况下,UTF-8 可用正则表达式检索而GBK不行。
其他
与其他 Unicode 编码相比,特别是UTF-16,在 UTF-8 中 ASCII 字元占用的空间只有一半,可是在一些字元的 UTF-8 编码占用的空间就要多出,特别是中文、日文和韩文(CJK)这样的象形文字,所以具体因素因文档而异,但不论哪种情况,差别都不可能很明显。
呵呵,自从可以访问WiKi以后,基本成了一些名字解释等信息的重要来源了。。。。希望以后可以一直访问到。(个人想法)
另外,对于服务器来讲,调试信息的主要出口在两个地方,一个是记录日志文件,一个就是控制台输出了,按我们总监的话来说@#¥@#……¥#算了,不说了,反正总监的大意就是服务器就是看着一屏屏的文字,没有写客户端代码那样有成就感,能够即时的显示出来,但是,别小看这些文字,很多bug调试的时候不一定能出来,偶尔出现一次,基本得靠日志分析,而控制台的输出主要目的可能就是即时的对服务器运行状况有所了解(其实真正后期运行个人感觉并不是太主要),主要的还是以文件形式记录的日志,而且控制台的输出对于效率的影响过大。(其实所有的I/O操作都是相对来说很耗时间的)
正在世界地图服务器,这里讲一个插曲,我们公司的服务器日志目前全部是英文................呵呵,原因是Linux下的中文输出有问题-_-!当然有问题,公司为了保证游戏客户端的效率,所有的字符处理全部是以UCS-2编码的两字节wchar_t来表示,不经过任何转换能显示出来才怪了-_-!。。。。。
首先是控制台的输出,Windows下:
一般来说,用VS2005中用wchar_t来表示UTF16中文就比较合适了,因为目前VS2005中wchar_t默认就是两字节的,下面是演示过程的源代码:
// Unicode.cpp : 定义控制台应用程序的入口点。
//
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <locale.h>
#include "ConvertUTF.h"
int _tmain(int argc, _TCHAR* argv[])
{
setlocale(LC_ALL, "");
wprintf(L"windows控制台在C语言中输出UCS-2宽字节中文-----begin-----/n");
ConversionResult result = sourceIllegal;
wchar_t lwcBuf[3] = L"中文";
UTF16 utf16_buf[3] = {0};
utf16_buf[0] = 0x4e2d;
utf16_buf[1] = 0x6587;
utf16_buf[2] = 0;
UTF16 *utf16Start = utf16_buf;
UTF8 utf8_buf[12] = {0};
UTF8* utf8Start = utf8_buf;
wprintf(L"%s/n", (wchar_t*)utf16_buf);
wprintf(L"%s/n", lwcBuf);
result = ConvertUTF16toUTF8((const UTF16 **) &utf16Start, &(utf16_buf[3]), &utf8Start, &(utf8_buf[12]), strictConversion);
switch (result) {
default: fprintf(stderr, "Test02B fatal error: result %d for input %08x/n", result, utf16_buf[0]); exit(1);
case conversionOK: break;
case sourceExhausted: printf("sourceExhausted/t"); exit(0);
case targetExhausted: printf("targetExhausted/t"); exit(0);
case sourceIllegal: printf("sourceIllegal/t"); exit(0);
}
printf("is leagal UTF8: %d/n", isLegalUTF8Sequence(utf8_buf, utf8Start));
printf("%s/n", (char*)utf8_buf);
// 清空缓存,以确定以后的值的确是转换得来
ZeroMemory(utf16_buf, sizeof(utf16_buf));
// 由于转换中利用了这两个start,所以需要重新为start定位,并且保存住End值
UTF8* utf8End = utf8Start;
utf8Start = utf8_buf;
utf16Start = utf16_buf;
result = ConvertUTF8toUTF16((const UTF8 **) &utf8Start, utf8End, &utf16Start, &(utf16_buf[3]), strictConversion);
switch (result) {
default: fprintf(stderr, "Test02B fatal error: result %d for input %08x/n", result, utf16_buf[0]); exit(1);
case conversionOK: break;
case sourceExhausted: printf("sourceExhausted/t"); exit(0);
case targetExhausted: printf("targetExhausted/t"); exit(0);
case sourceIllegal: printf("sourceIllegal/t"); exit(0);
}
wprintf(L"%s/n", (wchar_t*)utf16_buf);
wprintf(L"windows控制台在C语言中输出UCS-2宽字节中文-----end-----/n");
return 0;
}
运行结果:
windows控制台在C语言中输出UCS-2宽字节中文-----begin-----
中文
中文
is leagal UTF8: 1
涓枃
中文
windows控制台在C语言中输出UCS-2宽字节中文-----end-----
还是利用了上一篇提到的函数,需要注意的是在C语言中不使用setlocale函数是没有办法正确输出utf16中文的,(因为默认可能是使用了windows以前的codepage那一套系统)设置后一切非常正常。无论是用short标志的中文,或者是直接输入的中文,控制台都能正确输出,但是utf8显然没有得到MS的支持,一样的,在VS2005中,UTF8字符不能正常的通过鼠标停留显示出来。。。。
以上是C语言的方案,C++的输出方式如下:(从原来的代码改过来的,有点乱,但是仅仅作为测试,没有考虑那么多了)
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <locale.h>
#include <iostream>
#include "ConvertUTF.h"
using namespace std;
void TestInCPP()
{
// 未为wcout流设置locale前的效果,cout能够输出中文是因为Windows以前的多字节技术
cout <<"未为wcout流设置locale前的效果: /"";
wcout <<L"中文";
cout <<"/"" <<endl;
// 可以看到什么效果都没有,还会将wcout设置错误标志位,不清楚此标志位将什么输出都没有
wcout.clear();
wcout.imbue(locale(""));
wcout <<L"windows控制台在C++语言中输出UCS-2宽字节中文-----begin-----/n" <<endl;
ConversionResult result = sourceIllegal;
wchar_t lwcBuf[3] = L"中文";
UTF16 utf16_buf[3] = {0};
utf16_buf[0] = 0x4e2d;
utf16_buf[1] = 0x6587;
utf16_buf[2] = 0;
UTF16 *utf16Start = utf16_buf;
UTF8 utf8_buf[12] = {0};
UTF8* utf8Start = utf8_buf;
wcout<<L"utf16_buf:" <<(wchar_t*)utf16_buf <<L" lwcBuf:" <<lwcBuf <<endl;
result = ConvertUTF16toUTF8((const UTF16 **) &utf16Start, &(utf16_buf[3]), &utf8Start, &(utf8_buf[12]), strictConversion);
switch (result) {
default: fprintf(stderr, "Test02B fatal error: result %d for input %08x/n", result, utf16_buf[0]); exit(1);
case conversionOK: break;
case sourceExhausted: printf("sourceExhausted/t"); exit(0);
case targetExhausted: printf("targetExhausted/t"); exit(0);
case sourceIllegal: printf("sourceIllegal/t"); exit(0);
}
wcout <<L"Is leagal UTF8:" <<isLegalUTF8Sequence(utf8_buf, utf8Start) <<endl;
cout.imbue(locale(""));
cout <<(char*)utf8_buf <<endl;
// 清空缓存,以确定以后的值的确是转换得来
ZeroMemory(utf16_buf, sizeof(utf16_buf));
// 由于转换中利用了这两个start,所以需要重新为start定位,并且保存住End值
UTF8* utf8End = utf8Start;
utf8Start = utf8_buf;
utf16Start = utf16_buf;
result = ConvertUTF8toUTF16((const UTF8 **) &utf8Start, utf8End, &utf16Start, &(utf16_buf[3]), strictConversion);
switch (result) {
default: fprintf(stderr, "Test02B fatal error: result %d for input %08x/n", result, utf16_buf[0]); exit(1);
case conversionOK: break;
case sourceExhausted: printf("sourceExhausted/t"); exit(0);
case targetExhausted: printf("targetExhausted/t"); exit(0);
case sourceIllegal: printf("sourceIllegal/t"); exit(0);
}
wcout<<L"utf16_buf:" <<(wchar_t*)utf16_buf <<endl;
wcout <<L"windows控制台在C++语言中输出UCS-2宽字节中文-----end-----/n" <<endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
TestInCPP();
return 0;
}
可以看到,C++的使用方法更加有效一些,因为仅仅影响到某个特定的输出流,而不是对所有的东西都一次性更改,这点与C++中面向对象的思想相符合,C语言那种方式太霸道了一点(符合C语言全局设定的风格)。但是作为操作系统的特性,C++也没有办法超越,去将UTF-8编码的字符串输出。
所以,最后的结论是,要在windows的控制台输出UTF-8编码的字符串似乎唯一的办法就是先转换成UCS-2然后再输出了。-_-!
这里要提及的就是同时使用两种机制会有冲突,记得当时看到有文章说,C与C++的这两种机制最好不要混用-_-!
write by 九天雁翎(JTianLing) -- www.jtianling.com
阅读全文....
UCS-2与UTF8之间的选择(2)--Unicode组织提供的C/C++的Unicode编码转换函数
write by 九天雁翎(JTianLing) -- www.jtianling.com
讨论新闻组及文件
这里我大概搜索到了3个库,一个是Unicode组织自己提供的,一个是IBM做的开源ICU工程中的,一个是开源的UCData 2.9。
但是UCData2.9中并没有UTF-16,通篇都是为UTF-32设计的,属于那种将来可能会用的到的库,因为目前Windows与Linux的内核都还没有UTF-32化,注定假如使用UTF-32将会在两个地方都失去性能优势。
于是剩下的两个选择就很有意思了,一个是Unicode自己提供的那几个简单的转换函数,一个是IBM提供的一个巨无霸的库,一个Unicode的相关库到了10M的确算是很夸张的了,难怪被别人称作蓝色巨人,干什么都是大手笔,就像它出品的软件工程软件一样,哪一个都是出手不凡,一出一个系列,每个都大的要命。感叹。。。。。
从C/C++的库的角度,我就只查看这两个了。
Unicode组织的函数:(甚至不能称作库)
这些函数很好用,并且自带了测试套件。
在windows中,新建一个空的工程,并将ConvertUTF.h,CVTUTF7.h,CVTUTF7.C,harness.c添加到工程中,编译,运行,既可以运行测试例程,utf7这个我们一般用不上,其实也可以不添加。在我的VS2005 SP1中,运行结果如下:
Three tests of round-trip conversions will be performed.
One test of illegal UTF-32 will be peroformed.
Two illegal result messages are expected; one in test 02A; one in test 03A.
These are for tests of Surrogate conversion.
Begin Test01
******** Test01 succeeded without error. ********
Begin Test02
Test02A for 55296, input 0000d800, output 0000,0000, result 3
!!! Test02A: note expected illegal result for 0x0000D800
******** Test02 succeeded without error. ********
Begin Test03
sourceIllegal Test03A for 55296 (0xd800); output ; result 3
!!! Test03A: note expected illegal result for 0x0000D800
******** Test03 succeeded without error. ********
Begin Test04
******** Test04 succeeded without error. ********
很显然的4个测试全部通过,没有任何错误。
提供的我们可能需要的函数有:
isLegalUTF8Sequence()—判断一个字符串是否是合法的UTF8字符串
ConvertUTF8toUTF16()—转换UTF8字符串到UTF16
ConvertUTF16toUTF8()—转换UTF16字符串到UTF8
原型:
ConversionResult ConvertUTF8toUTF16 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF16toUTF8 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
所有的函数采取的结尾判断方式是传递一个结束的指针位置,而不是常见的长度。
其提供的几个宏也很有用:
typedef unsigned long UTF32; /* at least 32 bits */
typedef unsigned short UTF16; /* at least 16 bits */
typedef unsigned char UTF8; /* typically 8 bits */
typedef unsigned char Boolean; /* 0 or 1 */
Boolean在C++中似乎是不怎么需要.
/* Some fundamental constants */
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
#define UNI_MAX_BMP (UTF32)0x0000FFFF
#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
很有价值的几个宏,除了都强制转换为UTF32比较郁闷,UNI_MAX_BMP,UNI_MAX_UTF16可以用的上。
typedef enum {
conversionOK, /* conversion successful */
sourceExhausted, /* partial character in source, but hit end */
targetExhausted, /* insuff. room in target for conversion */
sourceIllegal /* source sequence is illegal/malformed */
} ConversionResult;
这是上述那几个函数的返回值,英文注释解释的很清楚了。
typedef enum {
strictConversion = 0,
lenientConversion
} ConversionFlags;
这是那几个函数的第五参数,一个表示严格转换,一个表示宽容的转换
排除harness.c,不编译,添加ConvertUTF.c,自己制作一个测试:
// Unicode.cpp : 定义控制台应用程序的入口点。
//
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include "ConvertUTF.h"
int _tmain(int argc, _TCHAR* argv[])
{
ConversionResult result = sourceIllegal;
UTF16 utf16_buf[8] = {0};
utf16_buf[0] = 0xd834;
utf16_buf[1] = 0xdf00;
utf16_buf[2] = 0xd834;
utf16_buf[3] = 0xdf01;
utf16_buf[4] = 0xd834;
utf16_buf[5] = 0xdf02;
utf16_buf[6] = 0;
utf16_buf[7] = 0;
UTF16 *utf16Start = utf16_buf;
UTF8 utf8_buf[16] = {0};
UTF8* utf8Start = utf8_buf;
MessageBoxW(NULL, (LPWSTR)utf16_buf, L"Before trans", MB_OK);
result = ConvertUTF16toUTF8((const UTF16 **) &utf16Start, &(utf16_buf[6]), &utf8Start, &(utf8_buf[16]), strictConversion);
switch (result) {
default: fprintf(stderr, "Test02B fatal error: result %d for input %08x/n", result, utf16_buf[0]); exit(1);
case conversionOK: break;
case sourceExhausted: printf("sourceExhausted/t"); exit(0);
case targetExhausted: printf("targetExhausted/t"); exit(0);
case sourceIllegal: printf("sourceIllegal/t"); exit(0);
}
// 清空缓存,以确定以后的值的确是转换得来
ZeroMemory(utf16_buf, sizeof(utf16_buf));
// 由于转换中利用了这两个start,所以需要重新为start定位,并且保存住End值
UTF8* utf8End = utf8Start;
utf8Start = utf8_buf;
utf16Start = utf16_buf;
result = ConvertUTF8toUTF16((const UTF8 **) &utf8Start, utf8End, &utf16Start, &(utf16_buf[6]), strictConversion);
switch (result) {
default: fprintf(stderr, "Test02B fatal error: result %d for input %08x/n", result, utf16_buf[0]); exit(1);
case conversionOK: break;
case sourceExhausted: printf("sourceExhausted/t"); exit(0);
case targetExhausted: printf("targetExhausted/t"); exit(0);
case sourceIllegal: printf("sourceIllegal/t"); exit(0);
}
MessageBoxW(NULL, (LPWSTR)utf16_buf, L"After Trans", MB_OK);
return 0;
}
利用的还是以前的太玄经字符,经测试,两次的MessageBox显示均正常,唯一需要注意的是由于转换函数的第1,3个参数都是以指针的指针为参数,并且跟进实现中可以发现,实现中利用了此指针的偏转来完成长度的判断,并且利用此值作为结束的返回,好处自然是还是以指针作为结束的返回了,坏处就是你需要重新利用的时候需要重新定位。如上述源代码及中间的注释所示,这可能也就是这些函数唯一需要注意的地方了,因为和平时对长度的判断不同。
至于为什么要这样做,可能是出于效率的考虑,就像C语言中以NULL为字符串的结束标志而不是在字符串前加一个长度一样,虽然此点因为容易导致严重的越界问题而被人诟病,但是实际上,这样比记长度能够更加有效率的处理字符串是很多人没有发现的。
当以某个值为结束标志(比如C 语言中的NULL)时,遍历只需要偏移起始指针,并在循环每次做一个判断,大概如下形式,这样每次循环只需要一次的比较,一次的++。
for(; p != NULL; ++p)
{
// 此处可以直接处理*p了
}
假如是长度呢?
可能需要如下形式,一方面需要额外的一个临时变量,一方面对字符串中值的调用效率也更加低了。而这些消耗在以’/0’结尾时就不存在。
for(int i = 0; i < END; ++i)
{
// p[i]或者p+i的处理方式
}
这点也很好解释,为什么到了C++中迭代器还是喜欢用类似的形式:)
for(lit = container.begin(); lit != container.end(); ++lit)
{
// 直接使用 *lit
}
这在效率至上的世界中,很好理解。
write by 九天雁翎(JTianLing) -- www.jtianling.com
阅读全文....
服务器Select模型的实现
write by 九天雁翎(JTianLing) -- www.jtianling.com
讨论新闻组及文件
select模型属于网络的I/O复用模型,比纯粹的阻塞I/O模型更具有实用性,因为可以同时等待多个描述字的就绪。
当年学习C/C++的时候,很少碰到底层以数字标示的描述字,只在写文件系统的去尝试各种情况,以获得最佳效率的时候实际尝试使用过一次,一直觉得那种open,write,read的文件操作方式,实在是比fopen一族函数还要低级的方式-_-!平时没有必要使用。但是等到网络编程的时候,才发现。。。。原来这么底层的东西,竟然也有一定的通用性,文件的描述字和网络的描述字竟然是一致的-_-!不管是谁设计的,还是挺佩服的。。。。。。
这里仅仅是为了学习Select模型而写的学习例子,作用是在服务器端输出连接上的客户端的IP(仅以数字形式),然后将客户端的IP以字符串的形式返回,客户端连接服务器,并接受由服务器端返回的IP地址,然后输出转换为字符串形式的IP地址和数字形式的IP地址,为了区别select到正确的不同listen套接字,这里用了不同的端口,并且不同的两个套接字响应时以echo 1,echo 2区别。功能是很简单的,仅仅用于学习,所以其中很多地方本来可以抽出来称为函数的,都贪简单,直接复制了(-_-!这里本来习惯想说Ctrl-C Ctrl-V的。。。但是发现自己实在Ubuntu下用vim复制的,好像和实际情况不符。。。。)
另外。。。。由于用的是《Unix Network Programming》一书,所以编程风格都变得有点像书中了。。。。服务器端全是自己写的,客户端代码由书中的daytime客户端改过来的,并且发现书中客户端代码都不关闭套接字,都交由退出进程的时候由系统关闭,不知道这种风格好不好。由于学习。。。写的是ANSI C程序,用gcc编译-_-!
unp.h是《Unix Network Programming》源代码中的公用头文件,makefile可能也得注意一下,为了图省事,我用了其源代码中的Make.defines,因为这样比自己写简单多了:),makefile就不贴了,没有什么学习意义。
运行效果如下:
客户端运行:
./TestSelectCli 127.0.0.1 1000
Conncet OK
127.0.0.1:16777343 Echo 1.
laptop:~/unpv1/unpv13e/MyTest$ ./TestSelectCli 127.0.0.1 1001
Conncet OK
127.0.0.1:16777343 Echo 2.
laptop:~/unpv1/unpv13e/MyTest$ ./TestSelectCli 192.168.0.138 1000
Conncet OK
192.168.0.138:2315299008 Echo 1.
laptop:~/unpv1/unpv13e/MyTest$ ./TestSelectCli 192.168.0.138 1001
Conncet OK
192.168.0.138:2315299008 Echo 2.
服务器端输出:
2315299008 Echo 1.
16777343 Echo 1.
16777343 Echo 2.
2315299008 Echo 1.
2315299008 Echo 2.
服务器端源代码:
1 #include "unp.h"
2
3
4 void str_echo1(int connfd);
5 void str_echo2(int connfd);
6
7 int main(int argc, char **argv)
8 {
9 struct sockaddr_in cliaddr;
10 pid_t childpid;
11
12 /* Bind 1000 port to listen socket 1 */
13 int listenfd1 = Socket(AF_INET, SOCK_STREAM, 0);
14
15 struct sockaddr_in servaddr;
16 bzero(&servaddr, sizeof(servaddr));
17 servaddr.sin_family = AF_INET;
18 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
19 servaddr.sin_port = htons(1000);
20
21 Bind(listenfd1, (SA *)&servaddr, sizeof(servaddr));
22
23 Listen(listenfd1, LISTENQ);
24
25 /* Bind 1001 port to listen socket 2*/
26 int listenfd2 = Socket(AF_INET, SOCK_STREAM, 0);
27
28 struct sockaddr_in servaddr2;
29 bzero(&servaddr2, sizeof(servaddr2));
30 servaddr2.sin_family = AF_INET;
31 servaddr2.sin_addr.s_addr = htonl(INADDR_ANY);
32 servaddr2.sin_port = htons(1001);
33
34 Bind(listenfd2, (SA *)&servaddr2, sizeof(servaddr2));
35
36 Listen(listenfd2, LISTENQ);
37
38 /* Initialize fd_set struct */
39 int maxfdp1 = max(listenfd1, listenfd2) + 1;
40 fd_set rset;
41 FD_ZERO(&rset);
42
43 /* Select from this two listen socket */
44 for( ; ; )
45 {
46 FD_SET(listenfd1, &rset);
47 FD_SET(listenfd2, &rset);
48
49 int nready = -1;
50 if( (nready = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0)
51 {
52 if(EINTR == errno)
53 {
54 continue;
55 }
56 else
57 {
58 err_sys("Select error.");
59 }
60 }
61
62 /* some one listening socket is readable.*/
63 if(FD_ISSET(listenfd1, &rset))
64 {
65 socklen_t len = sizeof(cliaddr);
66 int connfd = Accept(listenfd1, (SA *)&cliaddr, &len);
67
68 if( 0 == (childpid = Fork()) )
69 {
70 /* child process */
71 Close(listenfd1);
72
73 str_echo1(connfd);
74 exit(0);
75 }
76
77 /* parent process */
78 Close(connfd);
79
80 }
81
82
83 if(FD_ISSET(listenfd2, &rset))
84 {
85 socklen_t len = sizeof(cliaddr);
86 int connfd = Accept(listenfd2, (SA *)&cliaddr, &len);
87
88 if( 0 == (childpid = Fork()) )
89 {
90 /* child process */
91 Close(listenfd2);
92
93 str_echo2(connfd);
94 exit(0);
95 }
96
97 /* parent process */
98 Close(connfd);
99
100 }
101
102 }
103
104 exit(0);
105 }
106
107 void str_echo1(int connfd)
108 {
109 struct sockaddr_in clientAddr;
110 socklen_t len = sizeof(clientAddr);
111
112 if(getpeername(connfd, (SA*) &clientAddr, &len) < 0)
113 {
114 return;
115 }
116
117 char lcBuffer[MAXLINE] = {0};
118 sprintf(lcBuffer, "%u Echo 1.", clientAddr.sin_addr.s_addr);
119
120 printf("%s/n", lcBuffer);
121
122 Write(connfd, lcBuffer, MAXLINE);
123 }
124
125
126 void str_echo2(int connfd)
127 {
128 struct sockaddr_in clientAddr;
129 socklen_t len = sizeof(clientAddr);
130
131 if(getpeername(connfd, (SA*) &clientAddr, &len) < 0)
132 {
133 return;
134 }
135
136
137 char lcBuffer[MAXLINE] = {0};
138 sprintf(lcBuffer, "%u Echo 2.", clientAddr.sin_addr.s_addr);
139
140 printf("%s/n", lcBuffer);
141
142 Write(connfd, lcBuffer, MAXLINE);
143 }
144
145
客户端源代码:
1 #include "unp.h"
2
3 int main(int argc, char **argv)
4 {
5 int sockfd, n;
6 char recvline[MAXLINE + 1];
7 struct sockaddr_in servaddr;
8
9 if (argc != 3)
10 err_quit("usage: a.out <IPaddress> <IPPort>");
11
12 int port = atoi(argv[2]);
13
14 if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
15 err_sys("socket error");
16
17 bzero(&servaddr, sizeof(servaddr));
18 servaddr.sin_family = AF_INET;
19 servaddr.sin_port = htons(port);
20 if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
21 err_quit("inet_pton error for %s", argv[1]);
22
23 if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)
24 err_sys("connect error");
25
26 printf("Conncet OK/n");
27
28 while ( (n = read(sockfd, recvline, MAXLINE)) > 0) {
29 recvline[n] = 0; /* null terminate */
30
31 /* change number string to number and to ip string */
32 struct in_addr svraddr;
33 svraddr.s_addr = strtoul(recvline, NULL, 10);
34 char *pszsvraddr = inet_ntoa(svraddr);
35
36 printf("%s:%s/n", pszsvraddr, recvline);
37 }
38 if (n < 0)
39 err_sys("read error");
40
41 exit(0);
42 }
write by 九天雁翎(JTianLing) -- www.jtianling.com
阅读全文....
确定Windows XP到底是UCS-2的还是UTF-16的
write by 九天雁翎(JTianLing) -- www.jtianling.com
讨论新闻组及文件
一般认为Windows下以16bit表示的Unicode并不是UTF-16,而是UCS-2。UCS-2是一种编码格式,同时也是指以一一对应关系的Unicode实现。在UCS-2中只能表示U+0000到U+FFFF的BMP(Basic Multilingual Plane ) Unicode编码范围,属于定长的Unicode实现,而UTF-16是变长的,类似于UTF-8的实现,但是由于其字节长度的增加,所以BMP部分也做到了一一对应,但是其通过两个双字节的组合可以做到表示全部Unicode,表示范围从U+0000 到 U+10FFFF。关于这一点,我在很多地方都看到混淆了,混的我自己都有点不太肯定自己的说法了,还好在《UTF-16/UCS-2》中还是区别开了,不然我不知道从哪里去寻找一个正确答案。(哪怕在IBM的相关网页上都将UCS-2作为UTF-16的别名列出)
在《UTF-16/UCS-2》文中有以下内容:
UTF-16 is the native internal representation of text in the Microsoft Windows 2000/XP/2003/Vista/CE; Qualcomm BREW operating systems; the Java and .NET bytecode environments; Mac OS X's Cocoa and Core Foundation frameworks; and the Qt cross-platform graphical widget toolkit.[1][2][citation needed]
Symbian OS used in Nokia S60 handsets and Sony Ericsson UIQ handsets uses UCS-2.
The Joliet file system, used in CD-ROM media, encodes filenames using UCS-2BE (up to 64 Unicode characters per file).
Older Windows NT systems (prior to Windows 2000) only support UCS-2.[3]. In Windows XP, no code point above U+FFFF is included in any font delivered with Windows for European languages, possibly with Chinese Windows versions.[clarification needed]
很明确的说明了Windows 2000以后内核已经是UTF-16的了,这点还真是与平时的感觉相违背,于是可以测试一下。在UTF-16的编码转换函数(Python实现)
中我在windows下输出了三个太玄经的字符,“
阅读全文....
windows/linux服务器程序支持库的开发(1)--UCS-2与UTF8之间的选择(1)
write by 九天雁翎(JTianLing) -- www.jtianling.com
讨论新闻组及文件
总体计划见:
此为序篇。
作为常常在windows下开发的人员,一般将windows下的Unicode实现直接称为Unicode,(比如我在前面就一直是这样做的),而把其他的Unicode实现称为更加具体的名称,比如UTF-8,UTF-16等,但是既然这里要讨论各种Unicode的实现,所以,还是得好好的区分一下,这里,将windows下的Unicode实现正名为UTF-16,但是遗憾的是,我发现Windows下的字符串处理函数实际仅仅是支持UCS-2的(在Window XP下测试结果),所以从编程的角度来讲,我们还是只能使用UCS-2,见文章《确定Windows XP到底是UCS-2的还是UTF-16的》,所以,这里都不混淆的情况下都以UCS-2代替。
以一个字符对应一个Unicode编码,并且要表达全部的Unicode编码,连普通的两个字节的wchar_t都不够,所以,现在有了新的UTF-32,gcc中wchar_t也默认已经是32位的了,顺应的就是这种潮流,毕竟,在现在,硬盘内存都当白菜卖了,相对而言,不在乎那么点空间,最最重要的是编程方便,还有速度。
关于此部分内容参看《UTF-16/UCS-2》。
关于Unicode的编码范围的内容参看《Mapping of Unicode character planes》。
名字缩写注释:
通用字符集 (Universal Character Set, UCS)
统一码转换格式(Unicode Transformation Format,UTF)
假如初次接触,那么要了解清楚Unicode还不是那么简单的事情,这是实话。当年语言编码混乱的时代,一种语言的软件不能正常的在另外语言的操作系统上显示,编多语言的程序是件非常痛苦的事情,编写一个可以在不同操作系统上都显示正确字符的软件那是高难度的事情。当时呼吁统一编码的呼声很高,原以为Unicode一出,将来的程序员将是无比幸福,甚至都不会了解什么叫编码,什么叫代码页(Codepage),因为已经不用考虑了。
但是,事实是残酷的,当Unicode比较普及了以后,由于历史的原因,光是Unicode本身的实现的种类过多,导致的各个操作系统不兼容的问题,都能够让程序员苦恼痛苦不已,比如,现在要做的UTF-8与UCS-2之间的选择。可能无论哪个初学windows的人都会迷惑于其A,W的函数结尾,初学MFC编程的人都会为其中大量的_T()使用感到莫名奇妙,这些,其实都是历史原因,为了当时一代程序员的理想,用一套源码,实现ASCII和UCS-2两套编码兼容。
由于Windows的内核都已经是UTF-16化了,所以实际的开发中,即使不用到除英语以外的语言,使用Unicode其实都是有益的,起码对于现在的速度比内存更重要的时候,一般是有益的,因为使用UCS-2最多是字符多占用了一倍的内存,而使用ASCII实际是影响了所有字符串有关的API函数调用的速度。对于现实中几乎完全不可能去使用ASCII编译程序的中国程序员,还是按照老美们为了他们的习惯去规定的_T()模式,至今,我还感叹不已,毕竟,计算机的教育水平,国外和国内的话语权不是一个量级的,个人也是几乎看着“洋书”成长的,啃过英文原版技术书籍,而且哪怕是中文版的MSDN其实也是英文居多,所以,我们竟然会有这样符合老美们特殊国情的编程习惯-_-!
闲话少说,关于Unicode的起源发展,我在一篇《UTF-8和Unicode的FAQ》文档中见到过。这里是其英文版《UTF-8 and Unicode FAQ for Unix/Linux》。
在Unicode组织的官方主页上 http://unicode.org/ 的顶头,有这么一段话:
Welcome! The Unicode Consortium enables people around the world to use computers in any language. Our members develop the Unicode Standard, Unicode Locales (CLDR), and other standards. These specifications form the foundation for software internationalization in all major operating systems, search engines, applications, and the Web.
他们一点也不夸张,Unicode正是所有主要操作系统,搜索引擎,应用程序和网页的软件国际化的基础。这里我突然想起以前给lua for windows提交的那个库中的bug时,lua for windows的作者竟然回了两个中文字“关心”给我^^(虽然我不知道什么意思),见《真高兴啊。。。。实际的为开源事业做了点点贡献:),很久前指出的一个lua stdlib的bug得到确认》这在以前是不可想象的,因为在以前,英文的操作系统中要输出并显示个中文谈何容易啊。
这里我引用MS的话来说明一下Unicode的威力:
“采用支持 Unicode 的单源代码库使开发时间得以缩短,Unicode 为 Microsoft 带来的好处是显而易见的。就 Windows® 2000 来说,在发布英文产品后需要花费几个月的时间来准备其本地化版本。而对于 Windows XP,这一周期已缩短为几周时间。”—MS《通过 Unicode 5.0 将您的应用程序应用到全球》
这就是Unicode的威力,为程序员节省的时间是从几个月到几周这个量级。
候选的UTF-8/UCS-2
现在开发软件用Unicode,当然是没有疑问了。在windows下面直接用UCS-2估计也没有疑问。但是考虑的可移植的时候,问题就来了,目前Linux的内核Unicode实现都是UTF-8的,并且gcc新版的wchar_t已经是新标准的4字节了,这样就算同样的宽字符接口,可能也不一定和windows的wchar_t兼容,要用同一套代码可能还得设置-fshort-wchar的编译选项,看看这样的mannul说明,就知道这样做不是什么长久之计(我们公司一直这样做):
-fshort-wchar
Override the underlying type for wchar_t to be short unsigned int instead of the default for the target. This option is useful for building programs to run under WINE.
Warning: the -fshort-wchar switch causes GCC to generate code that is not inary compatible with code generated without that switch. Use it to conform to a non-default application binary interface.
这样个人感觉也不是什么长久之记,其实还不如用UTF8方便,用UTF8的坏处很明显,那就是处理的函数少一些,而且,字符的长度不一,不如UNICODE好处理。
这里真是个两难的选择,我需要好好研究研究,以后暂时遵循这个规则,之所以说暂时,原因很简单,我个人认为,将来UTF-32才是主流的编码方式,并且UTF-32也是以后唯一需要的编码方式。
UTF8:
优点:
1.UCS 字符 U+0000 到 U+007F (ASCII) 被编码为字节 0x00 到 0x7F (ASCII 兼容)。 这意味着只包含 7 位 ASCII 字符的文件在 ASCII 和 UTF-8 两种编码方式下是一样的。意味着完美兼容ASCII。--《UTF-8 and Unicode FAQ》
2.Linux的内核是UTF88的,意味着在Linux下使用UTF8有得天独厚的优势。而且不仅仅是Linux,大量的开源计划(由于大部分开源计划都是围绕着Linux走的),包括网页,XML等也都是原生UTF-8的,可参考源程序范例更多。
3.由于其单字节编码的方式,不用考虑大头小头的字节序问题。
4.以英文为主的数据在存储时,占用的空间较小。
缺点:
1. 大量的组合字符(即用两个以上字节来表示一个字符),使得字符串的处理很不方便。有着和任何变长编码一样的痛苦。并且因为这个原因,当字符超出ASCII范围时,原有的C/C++字符串函数运行结果都不会是你想要的。
2. 以非ASCII字符为主的数据在存储时,占用空间较大。
UCS-2:
优点:
1.统一定长编码,都是两个字节对应一个字符,所以对于字符串的处理非常方便。没有变长的痛苦。大量的宽字节C/C++函数都可以直接使用。
2.Windows的内核是UTF-16的,但是由于UCS-2仅仅是UTF-16的一个子集,所以在Windows下使用UCS-2,有得天独厚的优势。另外,从资料上看,使用UTF-16/UCS-2的操作系统阵营比使用UTF-8的更加庞大。见《UTF-16/UCS-2
》的“Use in major operating systems and environments”一节,带来的好处是,在与不同语言/平台的程序(毕竟我要写的是网络程序)进行通信时,会更加方便。
缺点:
1.在 Unix 下使用 UCS-2 (或 UCS-4) 会导致非常严重的问题. 用这些编码的字符串会包含一些特殊的字符, 比如 '/0' 或 '/', 它们在 文件名和其他 C 库函数参数里都有特别的含义. 另外, 大多数使用 ASCII 文件的 UNIX 下的工具, 如果不进行重大修改是无法读取 16 位的字符的. 基于这些原因, 在文件名, 文本文件, 环境变量等地方, UCS-2 不适合作为 Unicode 的外部编码. --《UTF-8 and Unicode FAQ》,实际其意思就是原有的C语言字符串函数将完全失效,哪怕你用的就是ASCII字符也是这样。
上述的比较仅仅是理论上的,并且似乎难决高下,以下将具体的分别在Linux,Windows不同的环境下尝试使用UCS-2和UTF-8,以做出决定。
大概会尝试的有:
C/C++ 中使用,Python中使用,Lua中使用,正则表达式的使用。
之所以花这么多时间来研究这个问题,出于很多原因,有人说,编程的主要时间是花在进行字符串的处理上了,而现在这样的选择,将会决定以后我大部分时间是否是会更长,还是更短,是更容易,还是更难的问题。而且,对程序的效率,空间占用,肯定也是有影响的。对于初学者来说,一般用ANSI学习就完了,到了真实的使用,这些问题的考虑,甚至比可以想象的还要重要。
对于这个话题,著名开源计划Samba的发起人Andrew Tridgell,曾经在为Samba适应Windows的UCS-2时,提出了一个移植计划,一步一步的将Samba的内核从UTF-8移植到UCS-2. 《utf8 vs ucs2》,颇有味道:)对于同样致力于跨平台程序编写的我,也是指导意义很多。毕竟作为一个不准备在Windows下运行,而是仅仅需要与Windows进行通行的一个程序,最后都需要将内核全面的UCS-2化,而我的程序是不仅仅是需要与Windows下程序通信,并且还需要能够在Windows下运行的,是不是更应该用UCS-2呢?有待研究。另外,我还找到了一个在UNIX/Linux下使用UCS-2的范例:)开源就是好啊。
而我公司使用的是UCS-2,主要是因为客户端是肯定跑在Windows下而且是肯定不需要跑到Linux下的,而作为网络游戏,自然以客户端的效率为主,所以服务器多了一下无谓的字符转换操作也接受了。
UCS-2还是UTF-8,需要继续研究...................................
参考:
UTF-8, UTF-16, UTF-32 & BOM
UTF-16/UCS-2
Unicode详解—想当棒的中文讲解
write by 九天雁翎(JTianLing) -- www.jtianling.com
阅读全文....
UTF-16的编码转换函数(Python实现)
write by 九天雁翎(JTianLing) -- www.jtianling.com
讨论新闻组及文件
此函数用于将Unicode的编码用UTF-16编码方式表示出来,由于Unicode超过0xFFFF的编码需要用两个16bit联合来表示,所以看起来就没有0xFFFF以下那么一一对应看起来直观。为了使用方便,实现此函数。
其函数实现算法来自《UTF-16/UCS-2》
具体算法描述如下:
Example UTF-16 encoding procedure
The character at code point U+64321 (hexadecimal) is to be encoded in UTF-16. Since it is above U+FFFF, it must be encoded with a surrogate pair, as follows:
v = 0x64321
v′ = v - 0x10000
= 0x54321
= 0101 0100 0011 0010 0001
vh = 0101010000 // higher 10 bits of v′
vl = 1100100001 // lower 10 bits of v′
w1 = 0xD800 // the resulting 1st word is initialized with the high bits
w2 = 0xDC00 // the resulting 2nd word is initialized with the low bits
w1 = w1 | vh
= 1101 1000 0000 0000 |
01 0101 0000
= 1101 1001 0101 0000
= 0xD950
w2 = w2 | vl
= 1101 1100 0000 0000 |
11 0010 0001
= 1101 1111 0010 0001
= 0xDF21
The correct UTF-16 encoding for this character is thus the following word sequence:
0xD950 0xDF21
Python实现如下:
def EncodeUTF16(u):
vc = u - 0x10000
vh = (vc & 0xFFC00) >>10
vl = vc & 0x3FF
w1 = 0xD800
w2 = 0xDC00
w1 = w1 | vh
w2 = w2 | vl
return w1,w2
强大的Eclipse是我见过的第二个可以直接复制过来就有语法高亮和保持格式的编辑器/IDE,以前我见过的唯一一个就是MS它自己的VS。
用此算法计算《U1D300--Tai Xuan Jing(太玄经)Unicode编码.pdf》中前三个字符的数值,获得结果:
0x1D300
0xd834 0xdf00
0x1D301
0xd834 0xdf01
0x1D302
0xd834 0xdf02
然后因为X86的机器是小头机,用UltraEdit的16进制编辑模式,输入
00000002h: 34 D8 00 DF 34 D8 01 DF 34 D8 02 DF
用UTF-16模式保存后,前面加上了BOM,FF FE用于表示小头机,再换回文本模式你就能看到 “
阅读全文....
MSDN:为了防止数据丢失,请关闭文件后再删除它们
write by 九天雁翎(JTianLing) -- www.jtianling.com
讨论新闻组及文件
今天看ext lib的作者网页上写的,觉得挺有意思,大家也可以去看看:
http://mx-3.cz/tringi/www/langen.php?id=msdn&submenu=3
最绝的一条是:
DeleteFile
...
To prevent loss of data, close files before attempting to delete them.
...
为了防止数据丢失......请关闭文件后再删除它们-_-!
不过我的VS2005版本的MSDN已经没有这个了,不知道作者的版本是多少。
write by 九天雁翎(JTianLing) -- www.jtianling.com
阅读全文....
GNU的幽默
write by 九天雁翎(JTianLing) -- www.jtianling.com
GNU从名字开始幽默,GNU是GNU Not Unix的缩写。。。。-_-!
其主页上专门有一条GNU FUN:
http://www.gnu.org/fun/fun.html
其中最后的 Disclaim 如下:
Humor Submission Guidelines
Our policy for the humor page is that we will include something if all of these are true:
- It should be funny.
- It has no copyright problems.
- It is not libelous.
- It won't offend most ordinary hackers more than is reasonable in humor.
- The humor does not have to be computer-related.
GNUer是语言的发明创造专家和幽默大师,copyleft也来自这里,总之,他们喜欢与世界反着干.....
大部分的文章以声明(claim)结尾,其便以放弃(disclaim)结尾,大部分公司都是是将源代码作为最高机密,GNU却提倡开源,于是别人需要保留自己的copyright,GNU copyleft......其实copyleft也是收到保护的-_-!
这里从其中选一面贴过来:
from http://www.gnu.org/fun/jokes/declarations.html
Funny C/C++ declarations!
auto accident;
register voters;
static electricity;
struct by_lightning;
void *where_prohibited;
char broiled;
short circuit;
short changed;
long johns;
long dong_silver; /* Submitted by Juan Carlos Castro */
unsigned long letter;
double entendre;
double trouble;
union organizer;
union jack;
float valve;
short pants;
union station;
void check; unsigned check;
struct dumb by[sizeof member];
union onion; /*submitted by srp*/
/*if GCC extensions are allowed -- Dave Gilbert */
long long ago; /* in a galaxy far far away */
/* Submitted by James Buchanan */
const ipated;
case closed:
double or_nothing;
short sighted;
void if_removed; /* warranty */
volatile buggy_code;
unsigned anonymous;
int erbreed; /* duelling banjos */
/* Borland's additional C keywords */:
huge penis;
interrupt ed;
near sighted;
far out;
men()
{
goto pub;
pub:
return pissed;
}
women()
{
goto bathroom;
bathroom:
while (1) ;
}
class dismissed : public annoyance /* Submitted by Juan Carlos Castro */
The following was submitted by Pietro Gagliardi:
/* All this was done on August 17, 2007 by Pietro Gagliardi
You are free to use this code in a citation or (if you have the guts)
in your own program; just please mention me. */
typedef int number;
class microsoft : public corporation, public enemy<(number) 1> {
public:
microsoft()
{
sanity = 200;
bill_gates = drop_out();
ceo = bill_gates;
while (sanity > 2) {
sleep(2);
sanity--;
}
steve_ballmer = new class doofus;
}
#define our int
#define SUCCESS 1
our year_2006_goals()
{
delete bill_gates;
ceo = steve_ballmer;
sanity -= 200;
return SUCCESS;
}
protected:
int sanity;
class doofus ceo, bill_gates, steve_ballmer;
};
typedef int iq;
const iq of_steve_ballmer = -4, of_steve_jobs = MENSA_MINIMUM - 1,
of_linus_torvalds = MENSA_MINIMUM, of_bill_gates = UNDEFINED;
/* Here are some that make use of the preprocessor and the Unix programming interface */
#include <sys/types.h>
#define middle
middle class businessMan {
ino_t want_to_go_to_work;
#if speeding_to_work_because_you_are_late
off_t o_jail;
#endif
};
class mate
{
ino_t wannagotoskool;
};
class woman {
#define be
private:
be friend class of_girls;
off_t o_the_mall()
{
for (;;)
mall.go_to(rand()).shop();
}
};
class clown {
!friend class teacher;
friend class mate;
};
个人最为欣赏的是这两个函数的定义:
men()
{
goto pub;
pub:
return pissed;
}
women()
{
goto bathroom;
bathroom:
while (1) ;
}
男人就是去酒吧喝醉了回来的动物,女人就是进入浴室再也不出来的动物-_-!
write by 九天雁翎(JTianLing) -- www.jtianling.com
阅读全文....
从Unicode到太玄经
write by 九天雁翎(JTianLing) -- www.jtianling.com
讨论新闻组及文件
本来仅仅是想找个BMP以外的Unicode字段来验证一下我用Python写的用于UTF-16编码的函数,结果发现在Supplementary Multilingual Plane有这么一条,看起来比较突兀:Tai Xuan Jing Symbols (1D300–1D35F)-_-!进去看一下更加突兀了-_-!
太玄经的符号在Unicode有编码-_-!
作为Unicode学习的附加,顺便还了解了一下太玄经......................
Tai Xuan Jing
From Wikipedia, the free encyclopedia
Jump to: navigation, search
The text Tài Xuán Jīng ("Canon of Supreme Mystery", Chinese: 太玄經) was composed by the Confucian writer Yáng Xióng (Chinese: 揚雄/扬雄; pinyin: Yáng Xióng; Wade-Giles: Yang Hsiung; 53 BCE-18 CE). The first draft of this work was completed in 2BCE (in the decade before the fall of the Western Han Dynasty). This text is also known in the West as The Alternative I Ching and The Elemental Changes.
The Tai Xuan Jing symbols [1] represent a primary level of semantic notation in the text and are an extension of the Yì Jīng symbols. The mono-, di- and tetragrams consist of three monograms:
- the unbroken line ( ⚊) for heaven (Chinese: 天; pinyin: tiān),
- once broken line ( ⚋) for earth (Chinese: 地; pinyin: dì),
- twice broken line (
阅读全文....
加班到十点,没有时间,弄个输出套接字接收和返回的Buffer大小的程序
write by 九天雁翎(JTianLing) -- www.jtianling.com
讨论新闻组及文件
在Ubuntu8.04桌面版下,测试的结果为
Socket default Receive Buffer is 87380
Socket default Send Buffer is 16384
与作者在freebsd4.8中的稍有不同,接收缓冲区略大,发送缓冲区略小。
作者得出的结果分别是57344,32768
在我的系统中,接收的缓存实在是够大
源代码:
1 #include "unp.h"
2
3 int main(int argc, char **argv)
4 {
5 int sockfd, n;
6 /* struct sockaddr_in servaddr; */
7 int liRcvSize = 0;
8 socklen_t liRcvLen = sizeof(liRcvSize);
9 int liSndSize = 0;
10 socklen_t liSndLen = sizeof(liSndSize);
11
12 if ((sockfd = Socket(AF_INET, SOCK_STREAM, 0)) < 0)
13 {
14 err_sys("Socket Create failed/n");
15 }
16
17 if ( ( n = getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &liRcvSize, &liRcvLen) ) < 0)
18 {
19 err_sys("getsocketopt recv buffer run failed/n");
20 }
21
22 if ( ( n = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &liSndSize, &liSndLen) ) < 0)
23 {
24 err_sys("getsocketopt send buffer run failed/n");
25 }
26
27 close(sockfd);
28
29 printf("Socket default Receive Buffer is %d/n", liRcvSize);
30 printf("Socket default Send Buffer is %d/n", liSndSize);
31
32
33 exit(0);
34 }
Thread model: posix
gcc version 4.2.4 (Ubuntu 4.2.4-1ubuntu4)
纯ANSI C程序
write by 九天雁翎(JTianLing) -- www.jtianling.com
阅读全文....