我在这就不把网上的那些资料粘过来了,只讲讲我碰到的问题和问题的解决过程及解决这个问题的过程中碰到的各种困难和疑惑,做到现在问题还没有完全解决,还存在一些BUG,特别是代码部分,上层给过来给的编码有的时候是gb2312编码,有的时候却已经是UTF-8的编码了,郁闷中…..
问题是发生在我们的设备的设备名为中文的时候,当发生ip改变时通知ftp服务器:通过上传一个以设备名加时间的命名方式的中英混合的ip改变通知文件,告知客户ip有发生改变,串口的打印信息为501的参数错误导致的语法错,对通过serv-u架设的ftp服务器版本不一样产生的现象也是不一样的,更高版本的会出现乱码,但更低版本的会出现上传不了的现象。
出现了问题就要解决它,在解决它之前就要分析是什么原因导致了这种现象,怎样去解决:
既然ftp在设备名为中文的时候会抱错,那就应该是编码方式的问题了,或者是格式不对之类的,查看rfc959对照那些“必须”,“需要”,“建议”等的ftp命令,没有发现有什么不对,想想在设备名为全英文的时候能够正确发送就应该不会跟ftp发送命令有关,那就主要怀疑是编码方式的问题了。这个时候需要验证是编码方式的问题,我们知道通过IE打开ftp的目录及文件都能够正常显示中文,这个时候我用了抓包工具抓包看了一下,你会发现它有一个命令:opts utf-8 on,(rfc 2389)而我在我们设备的程序中ftp客户端的代码中没有找到这个选项命令,而且如果你可以用其他的ftp客户端登陆ftp服务器,如CuteFTP、LeapFTP、FlashFXP这些工具登陆的时候,你会发现他们在你serv-u架设后但没有作编码方法方面的设置的时候也是会显示乱码和出现501的参数错导致语法错误的情况,通过在网上看到得解决这些问题的办法是设置serv-u服务器得默认设置,于是我就跟老大说能不能让客户进行服务器得一些配置来解决这个问题,也就是说我们不需要做任何修改:在服务器限制和设置-ftp设置-opts utf8点击下面的全局属性-高级选项-对所有发送接受的文件夹和文件名以utf-8编码方式进行编码的勾去掉.这样对大部分ftp客户端能够上传中文的文件夹和文件名,但可能还是有乱码。老大说不能这样,我们的宗旨是要让客户用的最简便,能不设置就不设置。哎,烦……于是想能不能直接发送opts utf8 off来设置ftp服务器不是默认的utf-8的编码方式,这样就无需客户配置也不需要修改板子程序和客户端程序 (这个方法是我在书写本文的时候才回想起来的,这个方法可行(使用这个方法能够很快的把这个问题解决,相对是临时解决的),因为手动设置ftp服务器和发送命令的方式效果是等同的,当初也想到过,我们是这样想得:对于各种ftp的服务器,我们希望我们的程序能够尽量通用,也就是说希望能够对大多数的ftp服务器进行支持,商量还是直接对服务器发送uft-8设置命令,我们以后的各个配置、命令等网络传输的都需要转成utf-8的编码再给ftp服务器发送.).
于是我就想我是不是也通过发送命令使得ftp服务器对接受的文件夹名和文件名都以utf-8编码的发式进行编码,然后我们把我们要传送的文件名和文件夹名都转成utf-8的,于是我开始了试探:刚开始最容易想到的就是看看我们的交叉编译器库中有没有支持编码转换的函数,在网上查了点资料,了解到iconv这个家族函数库是可以帮我们解决这样的问题的,在我们板子程序中加入头文件,makefile加上链接库,报库不存在的错误,这个时候进编译器的库中去看发现没有这个库,自己移植一个吧:于是下了一个开源的libiconv的源代码,libiconv-19.2.tar.gz,移植了一下,生成一个静态库,链接到板子程序,能够正常编译并运行,而且问题也迎刃而解了。这个问题很简单,只需要调用iconv_open,iconv,iconv_close三个函数即可解决问题。这个时候我高兴起来了,但是高兴了半天之后,用ls –al查看编译出来的板子执行程序,居然由原来的700多KB猛增到1.3M,把我们整个开发组都吓坏了,老大这时发话了,不能这样,你必须缩小!
于是我又开始我的征程,修改编译条件:将所有能disable都disable掉了,还是这么大,当时也怀疑是因为这个库可能包含很多种编码之间的相互转换,于是就用configure –help看没有关于disable一些编码发式的转化的,居然没有!查找代码,不过确实也是鄙人知识浅薄,没能从代码中找到能减少空间的办法。
这个时候又开始想自己根据它的编码转换来自己写一个:gb2312转utf-8的。我就开始写啊:这个转换最主要的关键所在也就是gb2312转成unicode,再由unicode转utf-8就简单了,前面那个的转换需要查表,这个表的生成是可以用代码生成的:
在windows下生成编码转换表,
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
int main()
{
wchar_t wstr[8] = {0};
FILE *fp;
unsigned char rowCode,colCode;
char szStr[64] = {0};
char szErr[16] = {0};
char szBuff[2] = {0};
unsigned char row;
unsigned char col;
strcpy(szErr,"/*XX*/0x0000,");
fp = fopen("GB2Uni_LUT.h", "w+, ccs=UNICODE");
if(fp)
{
strcpy( szStr, "unsigned short Unicode[72][96]={/n");
fwrite(szStr,1,strlen(szStr),fp);
for(row = 0; row < 72;row++)
{
for(col = 0;col < 96;col++)
{
rowCode = (row + 16) + 0xA0;
colCode = col + 0xA0;
szBuff[0] = rowCode;
szBuff[1] = colCode;
if( MultiByteToWideChar(CP_THREAD_ACP,MB_ERR_INVALID_CHARS,szBuff,2,wstr,8))
{
sprintf(szStr,"/*%s%X*/0x%X,",szBuff,*((unsigned short*)szBuff),wstr[0]);
fwrite(szStr,1,strlen(szStr),fp);
}
else
{
fwrite( szErr, 1, 13, fp );
}
}
fwrite( "/n", 1, 1, fp );
}
strcpy( szStr, "};/n");
fwrite( szStr, 1, strlen( szStr ), fp );
fclose(fp);
}
return 0;
}
在linux下生成编码转换表,
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
//#include <windows.h>
int main()
{
wchar_t wstr[8];
FILE *fp;
unsigned char rowCode,colCode;
char szStr[64];
fp = fopen("GB2Uni_LUT.h", "w+, ccs=UNICODE");
if(fp)
{
strcpy( szStr, "unsigned short Unicode[72][96]={/n");
fwrite(szStr,1,strlen(szStr),fp);
char szBuff[2];
unsigned char row = 0;
unsigned char col = 0;
for(row = 0; row < 72;row++)
{
for(col = 0;col < 96;col++)
{
rowCode = row + 0xA0;
colCode = col + 0xA0;
szBuff[0] = rowCode;
szBuff[1] = colCode;
if( mbstowcs(wstr,szBuff,8))
{
sprintf(szStr,"/*%s%X*/0x%X,",szBuff,*((unsigned short*)szBuff),wstr[0]);
fwrite(szStr,1,strlen(szStr),fp);
}
else
{
fwrite( szErr, 1, 13, fp );
}
}
fwrite( "/n", 1, 1, fp );
}
strcpy( szStr, "};/n");
fwrite( szStr, 1, strlen( szStr ), fp );
fclose(fp);
}
return 0;
}
复制到板子的程序中,进行查表,这样gb2312转unicode也就简单了,网上有很多这方面的资料,我就不累赘说明了,最终问题解决
下面给出gb2312转utf-8的代码吧:
//存在累赘的变量,没有整理,只是调试用的程序,见笑了
char* encodeConv::GB2UTF_8(char *p_srcStr)
{
char* p_desStr = NULL;
assert(NULL != p_srcStr);
int isrcLen = strlen(p_srcStr);
int idesLen = isrcLen*2;
int x = 0;
int y = 0;
short s_Temp = 0;
p_desStr = new char[idesLen];
memset(p_desStr,0,idesLen*sizeof(char));
char chighChar = 0;
char clowChar = 0;
char *p_TempStr = p_desStr;
for(int k = 0;k < idesLen;k++)
{
printf("%x ",*(p_srcStr+k));
}
printf("/n");
while ('/0' != *p_srcStr)
{
if(((unsigned char)*(p_srcStr))>=0xA0)
{
printf("%s %d %x %x/n",__FILE__,__LINE__,*(p_srcStr+1),*p_srcStr);
//gb2312转unicdoe
chighChar = *p_srcStr-0xB0;//大端序
clowChar = *(p_srcStr+1)-0xA0;//
x = (int)chighChar;
y = (int)clowChar;
s_Temp = Unicode[x][y];//取unicode编码
printf("%s %d %d %d %d/n",__FILE__,__LINE__,x,y,s_Temp);
//unicdoe转utf-8
chighChar= (0xff00&s_Temp)>>8;
clowChar= (0x00ff&s_Temp);
char cTemp[3];
printf("%s %d %x %x/n",__FILE__,__LINE__,chighChar,clowChar);
cTemp[0] = 0xE0 | ((0xF0 & chighChar)>>4);
cTemp[1] = 0x80 | (((0x0F & chighChar)<<2) | ((0xC0 & clowChar)>>6));
cTemp[2] = 0x80 | (0x3F & clowChar);
printf("%s %d %x %x %x/n",__FILE__,__LINE__,cTemp[0],cTemp[1],cTemp[2]);
memcpy(p_desStr,cTemp,sizeof(cTemp));
p_desStr += 3;
p_srcStr += 2;
}
else
{
memcpy(p_desStr,p_srcStr,1*sizeof(char));
p_srcStr +=1;
p_desStr += 1;
}
}
idesLen = strlen(p_TempStr);
for(int j = 0;j < idesLen;j++)
{
printf("%x ",*(p_TempStr+j));
}
return p_TempStr;//记得外面要delete []p_TempStr;
}
通过这个方式可以解决问题,但是我自己写的那段代码调试了很长一段时间,其实还有一种更简单的方法:在客户端转!!!windows下gb2312转utf-8简单的很,只需十来行代码,后面我们商量确实用这种方法简便,但是我还是在努力调试我的程序,争取把这个知识都弄懂了,现在终于明白了是怎么一回事了.呵呵,付出也总算有点回报了……