C++定时器函数
我现在写一个有关定时器的函数,使用过程首先想到的是用SetTimer函数,但是这个函数是阻塞模式,即就是说,如果调用这个函数,程序就会一直阻塞在这个函数上,一直等待时间,调用自己的历程。
现在想实现一种功能,定时器到达一定时间间隔比如说 2 s,就向服务器发送一种报文,而这期间的其他时间,则发送另外一种数据报文。
各位大神,我将自己的一部分代码贴如下:
其中主程序部分:
printf("\n*******************客户端心跳程序****************************\n");
UINT timerid = SetTimer(NULL, 1, 3000, TimeProc);
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
if(msg.message==WM_TIMER)
{
DispatchMessage(&msg);
}
}
while (TRUE)
{
Ret = SendData(sHost);
if (Ret == -1)//函数返回-1,发送出错为且非阻塞,程序中断执行,直接返回
return-1;
elseif (Ret == 0)//发送失败,阻塞造成
Sleep(500);
Ret = RecvData(sHost);
if (Ret == -1)//接受失败
return -1;
elseif (Ret == 0)//服务其要求重发
sID--;
//下面进行超时判断,当超时标记 FLAG = 3;判断超时,自动断开连接
DWORDnowtime = GetTickCount();
if ((nowtime-LastTime)<TimeEnd)
{
if ((nowtime - LastTime) > TimeSpace){//超时一次,FLAG++操作一次
FLAG++;
}
elsecontinue;
}
elseif (FLAG>=2){//超时三次,退出程序
printf("超时");
return -1;
}
}
closesocket(sHost);
WSACleanup();
system("pause");
时间历程调用如下:
staticintxintiao = 0;
//该函数实现向服务器发送心跳,时间间隔是 2 s
voidCALLBACKTimeProc(HWND hwnd,
UINT message,
UINT idTimer,
DWORD dwTimer){
//设置发送数据包的格式
DATATOSENDtempdatatosend;
memset(tempdatatosend.Buffer,0,DATA_BUFSIZE);//没有任何数据
tempdatatosend.Buflen = 0;//纯数据长度是0
tempdatatosend.DataType = 'T';//报文格式是‘T’心跳测试
tempdatatosend.dwTime = GetTickCount();//报文中含有当前时间,供系统刷新用
tempdatatosend.Sequence = xintiao++;//该字段没有意义
//发送心跳数据包
intRet;
printf("发送心跳!\n");
Ret = send(sHost,(LPSTR)&tempdatatosend,sizeof(DATATOSEND),0);
LastTime = GetTickCount();
}
现在想让时间历程和发送正常数据报文(如下)分别按照定时实现:
//该函数实现通过套接字 s 将数据发送过去
intSendData(SOCKET s){
//system("cls");
char temp[DATA_BUFSIZE] = "hello!!!" ;
Sleep(2000);
/*
memset(temp,0,DATA_BUFSIZE);
//接受输入用户数据
printf("\n\t\t输入向服务器发送数据:\n");
gets(temp);
*/
PDATATOSEND pdatatosend;
pdatatosend = &dataToSend;
//将数据复制到发送缓冲中
ZeroMemory(pdatatosend->Buffer,DATA_BUFSIZE);
strcpy_s(pdatatosend->Buffer,temp);
//填充发送结构体中的其他数据
pdatatosend->Buflen = strlen(temp);//数据长度存储起来
pdatatosend->DataType = 'D';//发送的类型是‘D’即就是数据
pdatatosend->dwTime = GetTickCount();//保存当前时间
pdatatosend->Sequence = sID++;//包的序号,从0开始
intRet;
Ret = send(sHost,(LPSTR)pdatatosend,sizeof(DATATOSEND)+4,0);
if (Ret == SOCKET_ERROR)
{
Ret = WSAGetLastError();
if (Ret == WSAEWOULDBLOCK)//无法完成非阻塞套接字上的操作
{
return 0;
}
else{
printf("发送失败\n%d",WSAGetLastError());
return-1;
}
}
else{//成功发送,表示与服务器交互成功
LastTime = GetTickCount();
FLAG = 0;
printf("序号 %d 包已经正常发送!\n\n",sID - 1);
printf("客户端发送的时间:%d\n\n",pdatatosend->dwTime);
}
return1;
}
想问有没有不阻塞的实现方式,定时发送闹钟报文,而在这期间则发送报文?
[解决办法]
我看了一下MSDN:
UINT_PTR SetTimer(
__in HWND hWnd,
__in UINT_PTR nIDEvent,
__in UINT uElapse,
__in TIMERPROC lpTimerFunc
);
有这么一句:
hWnd [in]
HWND
Handle to the window to be associated with the timer. 【This window must be owned by the calling thread】. If a NULL value for hWnd is passed in along with an 【nIDEvent】 of an existing timer, that timer will be replaced in the same way that an existing non-NULL hWnd timer will be.
是什么意思呢?我琢磨了一下,大概是要你创建一个线程,并且通过【事件】去管理操作。
-------------------------
抛开这些不说,我看的出来你的代码的意思:
创建一个C/S程序,其中,保证相互发送程序包有时间间隔,并且有设定状态。
我的建议是:采用线程异步操作。
[解决办法]
SetTimer()函数会导致产生一个WM_TIMER消息,然后这个消息由你的WinProc()或者DefWindowProc()来处理,再由它们间接的调用用SetTimer()注册的timer回调.也就是说,SetTimer()应该用在基于消息循环结构的程序下.
lz之所以会堵塞并不使因为SetTimer()是阻塞的,应该是lz的程序不是基于消息循环结构,进而系统无法传递给存在的消息处理过程,从而WM_TIMER消息始终得不到处理,导致程序阻塞.
将程序改成基于消息驱动的方式应该能解决问题.
[解决办法]
没有必要2个线程,一个线程就够了。
[解决办法]
迄今为止只用过最后一个参数是NULL的SetTimer