标题
服务器之王! [坛主CLQ的服务器程序开发日记,综合了众多C/C++程序崩溃的原因,强烈推荐!]
clq
用两个普通锁来实现多读单写锁,即写的时候谁也不能读写,读的时候别人也可以读但不能写。一写之下发现还真不好实现。两个锁不好把握,而且读不是一味的放行,如果在它之前有一个写请求的话也要等待,这个逻辑特别难以实现。
具体演化的各个版本我放在“马上代码”版块,供大家参考。还未大量测试。切记切忌 :)
--------------------------------------------------
后记,还是移到这个版块来吧。
clq
有一个 down 机一直没解决,原来是 gdImageDestroy() 释放空指针会崩溃,真XX的。
--------------------------------------------------
//为了效率要用 gdFree 释放返回值
char * resize_image(const std::string fn, int new_W, int new_H, int & size)
{
FILE * old_fp = NULL;
FILE * new_fp = NULL;
gdImagePtr old_im = NULL;
gdImagePtr new_im = NULL; //图片旧、新图片句柄
char * old_fn = (char *)fn.c_str();//"C:\\Documents and Settings\\Administrator\\桌面\\1.jpg";
//char * old_fn = "C:\\Documents and Settings\\wilson\\桌面\\1.jpg";
//char * new_fn = "C:\\Documents and Settings\\Administrator\\桌面\\2.jpg";
//int A4_W = new_W;//40;//?
//int A4_H = new_H;//40;//?
//int new_W = 100;//新宽度
//int new_H = 100;//新高度
char * data = NULL;
log_cur(log_file);
//缩放//能否保存在内存中
if((old_fp=fopen(old_fn, "rb"))!=NULL)
{ //打开原图片文件
log_cur(log_file);
old_im=gdImageCreateFromJpeg(old_fp);//取得原图片句柄
log_cur(log_file);
if (old_im == NULL)
return NULL;
log_cur(log_file);
//计算高度//临时
//old_im->sx;//宽度
//old_im->sy;//高度
new_H = new_W * (((double)old_im->sy)/(double)(old_im->sx));
//计算高度//临时 _end;
//一定要销毁旧图片,以免内存泄露
fclose(old_fp);
//放在后面//gdImageDestroy(old_im);
//new_im = gdImageCreate(A4_W,A4_H); //创建新图片,取得句柄
// new_im = gdImageCreate(new_W, new_H); //创建新图片,取得句柄
new_im = gdImageCreateTrueColor(new_W, new_H); //创建新图片,取得句柄
//int white = gdImageColorAllocate(new_im, 255, 255, 255); //白色,做背景色
//int black = gdImageColorAllocate(new_im, 0, 0, 0); //黑色,做前景色
//gdImageCopyResized 的效果大家都说不好
// gdImageCopyResized(new_im,old_im,0,0,0,0,new_W,new_H,old_im->sx,old_im->sy);//复制并缩放图片,new_W,new_H,新图片的宽高
gdImageCopyResampled(new_im,old_im,0,0,0,0,new_W,new_H,old_im->sx,old_im->sy);//复制并缩放图片,new_W,new_H,新图片的宽高
/*
if((new_fp=fopen(new_fn,"wb"))!=NULL)
{ //打开新文件
gdImageJpeg(new_im,new_fp,-1); //输出图片到文件
fclose(new_fp);
};
fclose(old_fp);
*/
//data = (char *) gdImagePngPtr(new_im, &size);
data = (char *) gdImageJpegPtr(new_im, &size, -1);//最后一个参数是什么意思?
if (!data)
{
//Error
return NULL;
}
};
log_cur(log_file);
//一定要销毁旧图片,以免内存泄露
//fclose(old_fp);
//放在后面//
if (old_im != NULL)
{
gdImageDestroy(old_im);
}
if (new_im != NULL)
{
gdImageDestroy(new_im);//这个会不会导致 data 失效呢?
}
return data;
//注意外层函数一定要调用这个//gdFree(data);
}
--------------------------------------------------
原因为少了这个
if (old_im != NULL)
没写上。唉,gd库的说明太少了。
clq
time() 出来的整数用 gmtime() 转换成结构,再转换成 time_t 的整数时,居然与最初 time() 出来的结果不同!整整少了8个小时,原来 mktime() 是与 localtime() 相对等的。真是有点奇怪哦。
//http://python.cn/pipermail/python-chinese/2005-September/016330.html
//mktime是time tuple -> local time
//gmtime是UTC time -> time tuple
//不是对等操作。
clq
c 中的 float 与 delphi 的 single 想等价,与 access 单精度字段也相等价.
f1:=20080321;//最后一位的精度会被去掉!
showmessage(floattostr(f1));
这样的结果是 20080320 !!真是的,在严肃的场合里还是用双精度吧。
clq
我坦白 :) 我对数据库的视图一向没有好印象,觉得都能用别的方式来实现。今天为了查看当天有多少个市场有数据于是写了如下语句:
select DISTINCT mark from symbol_tick
这个速度在有索引的情况下倒还比较快。然后想看 mark 对应的市场详细信息,就这样
select DISTINCT a.mark, b.en_name, b.cn_name from symbol_tick a
left join mark_info b on b.mark=a.mark
M呀,速度那叫一个慢,心想 mysql 咋就不知道先取到 mark 再 join 详细信息表呢。当然可以用临时表解决,但那写好多代码。想了想不知道现在的版本可以用视图了不,果然将第1个改为视图 v1 后再用下面的语句
select a.mark, b.en_name, b.cn_name from v1 a
left join mark_info b on b.mark=a.mark
快得不是一点点。
还顺便发现了一个保存 sql 语句的方法,以前老是想找能保存 sql 语句的 mysql 管理器,倒可以用它来代替一下 :)
clq
今天在 free() 内存的时候老是崩溃。找了好久,原来是有一处 memset() 时操作的长度超出了分配的长度。这在 VC6 的 debug 版本上会在 free 时崩溃,不过移植到 delphi 中时则是不会发生任何事情,看来在别的实现中也会有隐患。
另外一处是 delphi 的,操作一块内存惊奇的发现它中间的部分老是不对,一般情况下如果越界了会导致后面的内存都出错,仔细看了一下原来是分配的内存比指明的长度要小。写的内容越过了内存区在 delphi 下原来会这样 :)
clq
今天发现在取文件长度时返回值为 -1 调试了很久才发现是 vc6 的 release 版本下filelength() 函数的返回值有问题,不知道是不是我链接库有问题,比较安全的取文件长度的方法还是用 ftell。
--------------------------------------------------
unsigned long len = filelength(fileno(f));//vc6 的 release 下用 long 时会返回 -1
--------------------------------------------------
//文件长度//可以和 lockfile 一起用
static long get_file_length(FILE * f)
{//linux 下未测试//这样的实现不太好,最好还是用 ftell
long len = filelength(fileno(f));
//unsigned long len = filelength(fileno(f));//vc6 的 release 下用 long 时会返回 -1
if (f == NULL) return 0;
//#ifdef WIN32
//int no = fileno(pFile);
//len = filelength(no);
//奇怪, release 版本下有问题
//len = filelength(fileno(f));
//GetFileSize((HANDLE)_get_osfhandle(_fileno(pFile)), &len);
//#else
long lFileLen;//文件长度
long lFilePos;//当前位置
lFilePos = ftell(f);//得到当前位置
fseek(f, 0, SEEK_END);
lFileLen = ftell(f);
fseek(f, lFilePos, SEEK_SET);//回到原位置
len = lFileLen;
//#endif
return len;
}
clq
又碰到一次,非阻塞模式下 recv() 的返回值是 0 并不能判断为连接断开.
在 bsd 的编程当中说的是:如果 select 时发现有可读取数据但仍然返回 0 时就是断开,不过在 ppc 上好象行不通.感觉不太安全,安全的做法是尽量按平台的,平台以外的只用超时,以免出错,宁可连接断开的判断上有遗漏.
--------------------------------------------------
//if (r <= 0)
if (r < 0)
{
//到了连接被断开的时候WSAGetLastError返回既不是WSAECONNRESET也不是WSAECONNABORT。。。
int eno = WSAGetLastError();
//if (eno == WSAECONNRESET && eno == WSAECONNABORTED)
if (eno != WSAEWOULDBLOCK)//按 delphi ScktComp.pas 的源码,返回值为 0 时是不处理的,当返回值为 -1 时只要判断是否为 WSAEWOULDBLOCK 就可以了//发送时也是一样的
{
is_connect = false;//断开了
}
--------------------------------------------------
但是现在就有连接已经断开了,但 recv() 返回的是 0 而不是 -1 仍然无法检测到断开.客户端正常断开时为 0 ,强制断开时为 -1. 晕. 只能用超时?
clq
http://www.newbt.net:8022/read.csp?tid=2824&fpage=1
std::vector 取一个元素,其指针操作是不可用的?
这样取出来的指针是不可用的?
std::vector m_ThreadSendDataList;
//CThreadSendData & ThreadSendData = m_ThreadSendDataList[i];
//ThreadSendData.m_Thread = create_thread( (thread_func)&ThreadSendData.StartThread, &ThreadSendData);
--------------------------------------------------
总之这时候的 ThreadSendData 的指针值是不可用的,创建出来的线程会在锁定时死锁,原因未知,等俺哪天仔细研究一下 stl 先再说.
--------------------------------------------------
要这样
std::vector m_ThreadSendDataPointList;//发送数据包的线程//一个服务器用一个发送线程
CThreadSendData * pThreadSendData = new CThreadSendData();
pThreadSendData->m_Host = host;
pThreadSendData->m_iPort = atoi(port.c_str());
pThreadSendData->m_Thread = create_thread( (thread_func)&pThreadSendData->StartThread, pThreadSendData);
m_ThreadSendDataPointList[i] = pThreadSendData;
clq
妈妈呀,不同的时区 mktime 的结果是不同的!
void CTool1Dlg::OnButton4()
{
tm tm2;
memset(&tm2, 0, sizeof(tm));
tm2.tm_year = 70;
tm2.tm_mon = 0;
tm2.tm_mday = 1;
tm2.tm_hour = 8;//北京时间为 8 小时时差
//不等于程序所在的时区的话,下面的 t2 永远不会是 0 ,小于当地时区的话就会返回 -1 也就是失败
//也就是说 mktime 时按当地时间表示的 tm 结构来计算的!//但是又没有 gm_mktime 函数
//不过可以用 gmtime() 和 localtime() 设计出一个时区无关的 gm_mktime 函数来
time_t t2 = mktime(&tm2); // TODO: Add your control notification handler code here
t2 = 0;
tm * tm3 = gmtime(&t2);//这个时候要用 gmtime ,因是看结果,结果是要用格林威治时间表示的//test 看结果对不对
}
NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.