去年在博客里发这个贴时,只将主程序代码贴了出来,导致信息不完整,让读者根本无法进行实验。为此,现将全部代码贴出来,为想在linux下开发基于短信猫的短信收发程序的朋友提供一点参考。
首先,我根据功能需要创建了几个头文件,一个是stringex.h,包含一些字符串辅助函数;一个是inifile.h,包含读写类似windows环境下ini文件的函数;一个是daemon.h,包含创建linux守护进程(类似windows后台程序)的函数,还有一个是sms.h,包含串口通信相关函数,具体代码如下:
一、stringex.h,自定义字符串辅助函数库:
view plaincopy to clipboardprint?
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
文件名称:stringex.c
功能说明:字符串增强函数库
编者信息:lyserver
联系方式:http://blog.csdn.net/lyserver
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
#include
#include
#include
#ifndef STRING_EX_DEF
#define STRING_EX_DEF
const STRING_EX_BUFFER_SIZE=1023;
//定义自定义数据类型
typedef unsigned char BYTE;
typedef unsigned char *LPBYTE;
void ltrim(BYTE *outbuff,BYTE *inbuff); //截去左边的空格
void rtrim(BYTE *outbuff,BYTE *inbuff); //截去右边的空格
void alltrim(BYTE *outbuff,BYTE *inbuff); //截去左右的空格
void substr(BYTE *outbuff,BYTE *inbuff,int start,int length); //取子字符串
int instr(int start,BYTE *inbuff,BYTE *strfind); //查找在字符串inbuff中出现的strfind字符串位置
void replace(BYTE *outbuff,BYTE *inbuff,BYTE *strfind,BYTE *strreplace); //用strreplace替换字符串中出现的strfind
void str2hex(BYTE *outbuff,BYTE *inbuff); //将字符串转换成16进制
void hex2str(BYTE *outbuff,BYTE *inbuff); //将16进制字符串转换成字符串
int strconv(BYTE *outbuff,const BYTE *inbuff,BYTE *to_Charset,BYTE *from_Charset); //字符集转换(实现各种编码)
void ltrim(BYTE *outbuff,BYTE *inbuff) //截去左边的空格
{
int l;
BYTE *p=inbuff;
while(*p!='\0')
{
if(32!=(BYTE)*p)break;
p++;
}
l=strlen(inbuff)-(p-inbuff);
strncpy(outbuff,p,l);;
outbuff[l]='\0';
}
void rtrim(BYTE *outbuff,BYTE *inbuff) //截去右边的空格
{
int l;
BYTE *p=inbuff;
p+=(strlen(inbuff)-1);
while(p>inbuff)
{
if(32!=(BYTE)*p)break;
p--;
}
strcpy(outbuff,inbuff);
outbuff[p-inbuff+1]='\0';
}
void alltrim(BYTE *outbuff,BYTE *inbuff) //截去左右的空格
{
ltrim(outbuff,inbuff);
rtrim(outbuff,inbuff);
}
void substr(BYTE *outbuff,BYTE *inbuff,int start,int length) //取子字符串
{
if(start<0)start=0;
if(length>(strlen(inbuff)-start))length=strlen(inbuff)-start;
strncpy(outbuff,inbuff+start,length);
outbuff[length]='\0';
}
int instr(int start,BYTE *inbuff,BYTE *strfind) //查找strfind在字符串inbuff中出现的位置
{
BYTE *p;
if(strlen(strfind)==1)
{
p=strchr(inbuff+start,strfind[0]);
if(p!=NULL)
return p-inbuff;
else
return -1;
}
else
{
p=strstr(inbuff+start,strfind);
if(p!=NULL)
return p-inbuff;
else
return -1;
}
}
void replace(BYTE *outbuff,BYTE *inbuff,BYTE *strfind,BYTE *strreplace) //用strreplace替换字符串中出现的strfind
{
BYTE buff[STRING_EX_BUFFER_SIZE];
BYTE *p;
sprintf(buff,"%s%s",inbuff,strreplace);
p=strtok(buff,strfind);
outbuff[0]='\0';
while(p)
{
sprintf(outbuff,"%s%s%s",outbuff,p,strreplace);
p=strtok(NULL,strfind);
}
outbuff[strlen(outbuff)-strlen(strreplace)*2]='\0';
}
void str2hex(BYTE *outbuff,BYTE *inbuff)
{
int i;
unsigned long lASCII;
BYTE szbuff[STRING_EX_BUFFER_SIZE];
memset(szbuff,0,STRING_EX_BUFFER_SIZE);
for(i=0;i {
lASCII=0;
if(inbuff[i] < 0x80) //on BYTE of UTF8
{
lASCII = inbuff[i];
if(lASCII > 0xf)
sprintf(szbuff,"%s00%2X",szbuff,lASCII);
else
sprintf(szbuff,"%s000%1X",szbuff,lASCII);
}
else if((0xc0 <= inbuff[i]) && (inbuff[i] < 0xe0)) //tow BYTE of UTF8
{
lASCII = inbuff[i] & 0x1f;
lASCII = lASCII <<6;
lASCII = lASCII | (inbuff[i+1] & 0x3f);
sprintf(szbuff,"%s%2X",szbuff,lASCII);
i++;
}
else if((0xe0 <= inbuff[i]) && (inbuff[i] < 0xf0)) //three BYTE of UTF8
{
lASCII = inbuff[i] & 0x0f;
lASCII = lASCII << 6;
lASCII = lASCII | (inbuff[i+1] & 0x3f);
lASCII = lASCII <<6;
lASCII = lASCII | (inbuff[i+2] & 0x3f);
sprintf(szbuff,"%s%2X",szbuff,lASCII);
i+=2;
}
else//if((0x80 <=inbuff[i]) & (inbuff[i] < 0xc0)) //not the first byte of UTF8 BYTEacter
{
break;
}
}
strcpy(outbuff,szbuff);
}
void hex2str(BYTE *outbuff,BYTE *inbuff) //将16进制转为字符串
{
int i,iLen=strlen(inbuff);
BYTE szASCII[5];
BYTE szbuff[iLen];
unsigned long lASCII; //4位
if((iLen % 4)!=0) //如果长度不为4的倍数,则退出
{
outbuff[0]='\0';
return;
}
szbuff[0]='\0';
for(i=0;i {
szASCII[0]=inbuff[i];
szASCII[1]=inbuff[i+1];
szASCII[2]=inbuff[i+2];
szASCII[3]=inbuff[i+3];
szASCII[4]='\0';
lASCII=strtol(szASCII,'\0',16);
if(lASCII <= 0x007f) // on BYTE of UTF8
{
szASCII[0] = (BYTE)lASCII;
szASCII[1]='\0';
}
else if(lASCII <= 0x07ff) // two BYTE of UTF8
{
szASCII[1] = 0x80 | (BYTE)(lASCII & 0x003f);
szASCII[0] = 0xc0 | (BYTE)((lASCII >> 6) & 0x001f);
szASCII[2]='\0';
}
else // three BYTE of UTF8
{
szASCII[2] = 0x80 | (BYTE)(lASCII & 0x003f);
szASCII[1] = 0x80 | (BYTE)((lASCII >> 6) & 0x003f);
szASCII[0] = 0xe0 | (BYTE)((lASCII >> 12) & 0x001f);
szASCII[3]='\0';
}
strcat(szbuff,szASCII);
}
strcpy(outbuff,szbuff);
}
int strconv(BYTE *outbuff,const BYTE *inbuff,BYTE *to_Charset,BYTE *from_Charset) //字符集转换(实现各种编码)
{
iconv_t it;
size_t inleft=strlen(inbuff)+1;
size_t outleft=STRING_EX_BUFFER_SIZE;
char buff[STRING_EX_BUFFER_SIZE],*pbuff;
//打开需要转换的字符集
it=iconv_open(to_Charset,from_Charset);
if((int)it==-1)
return -1;
//进行转换
pbuff=buff;
memset(buff,0,STRING_EX_BUFFER_SIZE);
if((int)iconv(it,(char**)&inbuff,&inleft,(char**)&pbuff,&outleft)==-1)
return -2;
else
strcpy(outbuff,buff);
//转换结束
iconv_close(it);
return STRING_EX_BUFFER_SIZE-outleft;
}
#endif
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
文件名称:stringex.c
功能说明:字符串增强函数库
编者信息:lyserver
联系方式:http://blog.csdn.net/lyserver
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
#include
#include
#include
#ifndef STRING_EX_DEF
#define STRING_EX_DEF
const STRING_EX_BUFFER_SIZE=1023;
//定义自定义数据类型
typedef unsigned char BYTE;
typedef unsigned char *LPBYTE;
void ltrim(BYTE *outbuff,BYTE *inbuff); //截去左边的空格
void rtrim(BYTE *outbuff,BYTE *inbuff); //截去右边的空格
void alltrim(BYTE *outbuff,BYTE *inbuff); //截去左右的空格
void substr(BYTE *outbuff,BYTE *inbuff,int start,int length); //取子字符串
int instr(int start,BYTE *inbuff,BYTE *strfind); //查找在字符串inbuff中出现的strfind字符串位置
void replace(BYTE *outbuff,BYTE *inbuff,BYTE *strfind,BYTE *strreplace); //用strreplace替换字符串中出现的strfind
void str2hex(BYTE *outbuff,BYTE *inbuff); //将字符串转换成16进制
void hex2str(BYTE *outbuff,BYTE *inbuff); //将16进制字符串转换成字符串
int strconv(BYTE *outbuff,const BYTE *inbuff,BYTE *to_Charset,BYTE *from_Charset); //字符集转换(实现各种编码)
void ltrim(BYTE *outbuff,BYTE *inbuff) //截去左边的空格
{
int l;
BYTE *p=inbuff;
while(*p!='\0')
{
if(32!=(BYTE)*p)break;
p++;
}
l=strlen(inbuff)-(p-inbuff);
strncpy(outbuff,p,l);;
outbuff[l]='\0';
}
void rtrim(BYTE *outbuff,BYTE *inbuff) //截去右边的空格
{
int l;
BYTE *p=inbuff;
p+=(strlen(inbuff)-1);
while(p>inbuff)
{
if(32!=(BYTE)*p)break;
p--;
}
strcpy(outbuff,inbuff);
outbuff[p-inbuff+1]='\0';
}
void alltrim(BYTE *outbuff,BYTE *inbuff) //截去左右的空格
{
ltrim(outbuff,inbuff);
rtrim(outbuff,inbuff);
}
void substr(BYTE *outbuff,BYTE *inbuff,int start,int length) //取子字符串
{
if(start<0)start=0;
if(length>(strlen(inbuff)-start))length=strlen(inbuff)-start;
strncpy(outbuff,inbuff+start,length);
outbuff[length]='\0';
}
int instr(int start,BYTE *inbuff,BYTE *strfind) //查找strfind在字符串inbuff中出现的位置
{
BYTE *p;
if(strlen(strfind)==1)
{
p=strchr(inbuff+start,strfind[0]);
if(p!=NULL)
return p-inbuff;
else
return -1;
}
else
{
p=strstr(inbuff+start,strfind);
if(p!=NULL)
return p-inbuff;
else
return -1;
}
}
void replace(BYTE *outbuff,BYTE *inbuff,BYTE *strfind,BYTE *strreplace) //用strreplace替换字符串中出现的strfind
{
BYTE buff[STRING_EX_BUFFER_SIZE];
BYTE *p;
sprintf(buff,"%s%s",inbuff,strreplace);
p=strtok(buff,strfind);
outbuff[0]='\0';
while(p)
{
sprintf(outbuff,"%s%s%s",outbuff,p,strreplace);
p=strtok(NULL,strfind);
}
outbuff[strlen(outbuff)-strlen(strreplace)*2]='\0';
}
void str2hex(BYTE *outbuff,BYTE *inbuff)
{
int i;
unsigned long lASCII;
BYTE szbuff[STRING_EX_BUFFER_SIZE];
memset(szbuff,0,STRING_EX_BUFFER_SIZE);
for(i=0;i {
lASCII=0;
if(inbuff[i] < 0x80) //on BYTE of UTF8
{
lASCII = inbuff[i];
if(lASCII > 0xf)
sprintf(szbuff,"%s00%2X",szbuff,lASCII);
else
sprintf(szbuff,"%s000%1X",szbuff,lASCII);
}
else if((0xc0 <= inbuff[i]) && (inbuff[i] < 0xe0)) //tow BYTE of UTF8
{
lASCII = inbuff[i] & 0x1f;
lASCII = lASCII <<6;
lASCII = lASCII | (inbuff[i+1] & 0x3f);
sprintf(szbuff,"%s%2X",szbuff,lASCII);
i++;
}
else if((0xe0 <= inbuff[i]) && (inbuff[i] < 0xf0)) //three BYTE of UTF8
{
lASCII = inbuff[i] & 0x0f;
lASCII = lASCII << 6;
lASCII = lASCII | (inbuff[i+1] & 0x3f);
lASCII = lASCII <<6;
lASCII = lASCII | (inbuff[i+2] & 0x3f);
sprintf(szbuff,"%s%2X",szbuff,lASCII);
i+=2;
}
else//if((0x80 <=inbuff[i]) & (inbuff[i] < 0xc0)) //not the first byte of UTF8 BYTEacter
{
break;
}
}
strcpy(outbuff,szbuff);
}
void hex2str(BYTE *outbuff,BYTE *inbuff) //将16进制转为字符串
{
int i,iLen=strlen(inbuff);
BYTE szASCII[5];
BYTE szbuff[iLen];
unsigned long lASCII; //4位
if((iLen % 4)!=0) //如果长度不为4的倍数,则退出
{
outbuff[0]='\0';
return;
}
szbuff[0]='\0';
for(i=0;i {
szASCII[0]=inbuff[i];
szASCII[1]=inbuff[i+1];
szASCII[2]=inbuff[i+2];
szASCII[3]=inbuff[i+3];
szASCII[4]='\0';
lASCII=strtol(szASCII,'\0',16);
if(lASCII <= 0x007f) // on BYTE of UTF8
{
szASCII[0] = (BYTE)lASCII;
szASCII[1]='\0';
}
else if(lASCII <= 0x07ff) // two BYTE of UTF8
{
szASCII[1] = 0x80 | (BYTE)(lASCII & 0x003f);
szASCII[0] = 0xc0 | (BYTE)((lASCII >> 6) & 0x001f);
szASCII[2]='\0';
}
else // three BYTE of UTF8
{
szASCII[2] = 0x80 | (BYTE)(lASCII & 0x003f);
szASCII[1] = 0x80 | (BYTE)((lASCII >> 6) & 0x003f);
szASCII[0] = 0xe0 | (BYTE)((lASCII >> 12) & 0x001f);
szASCII[3]='\0';
}
strcat(szbuff,szASCII);
}
strcpy(outbuff,szbuff);
}
int strconv(BYTE *outbuff,const BYTE *inbuff,BYTE *to_Charset,BYTE *from_Charset) //字符集转换(实现各种编码)
{
iconv_t it;
size_t inleft=strlen(inbuff)+1;
size_t outleft=STRING_EX_BUFFER_SIZE;
char buff[STRING_EX_BUFFER_SIZE],*pbuff;
//打开需要转换的字符集
it=iconv_open(to_Charset,from_Charset);
if((int)it==-1)
return -1;
//进行转换
pbuff=buff;
memset(buff,0,STRING_EX_BUFFER_SIZE);
if((int)iconv(it,(char**)&inbuff,&inleft,(char**)&pbuff,&outleft)==-1)
return -2;
else
strcpy(outbuff,buff);
//转换结束
iconv_close(it);
return STRING_EX_BUFFER_SIZE-outleft;
}
#endif
二、inifile.h,配置文件读写函数库:
view plaincopy to clipboardprint?
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
文件名称:inifile.h
功能说明:配置文件读写函数库
编者信息:lyserver
联系方式:http://blog.csdn.net/lyserver
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
#ifndef INI_FILE_DEF
#define INI_FILE_DEF
#include
#include
#include
#include "stringex.h"
struct KEY_INFO
{
BYTE Name[64]; //Key名称
BYTE Value[64]; //Key值
LPBYTE pComment; //指向Key注释的指针
};
struct NODE_INFO
{
BYTE Name[64]; //节名称
LPBYTE pComment; //节注释
int iKeys; //键计数
struct KEY_INFO *pKeys; //键数组指针
};
struct FILE_INFO
{
FILE *hFile; //文件句柄
int iNodes; //文件包含的节数
struct NODE_INFO *pNodes; //节数组指针
struct NODE_INFO *pNode; //当前节指针
};
struct FILE_INFO *OpenIniFile(char *pFileName); //打开或创建配置文件
LPBYTE GetKeyValue(struct FILE_INFO *pFile,char *pNodeName,char *pKeyName);
int CloseIniFile(struct FILE_INFO *pFile); //关闭配置文件
struct FILE_INFO *OpenIniFile(char *pFileName) //打开或创建配置文件
{
int i,j; //临时变量,常常用于循环计数
static struct FILE_INFO m_File; //局部静态结构变量
int iFileSize=0,iLineType; //iFileSize:文件大小,iLineType:行类型
int KEY_SIZE=sizeof(struct KEY_INFO);
int NODE_SIZE=sizeof(struct NODE_INFO);
BYTE szLineBuff[256]; //szLineText行内容缓冲区
LPBYTE pFileText=NULL,pLine=NULL; //pFileText:配置文件内容缓冲区,pLine:行内容指针,p:临时字符串指针
m_File.hFile=NULL;
m_File.iNodes=0;
m_File.pNode=NULL;
m_File.pNodes=NULL;
if((m_File.hFile=fopen(pFileName,"r"))==NULL) //如果文件不存在
return(NULL);
//取文件长度
fseek(m_File.hFile,0,SEEK_END);
iFileSize=ftell(m_File.hFile);
if(iFileSize == 0) //如果长度等于0,返回创建的文件指针
return(NULL);
//读配置文件到缓冲区
fseek(m_File.hFile,0,SEEK_SET);
pFileText = (char*)malloc(iFileSize+2); //申请内存,大小为文件长度+2(防止内存溢出)
memset(pFileText,0,iFileSize+1);
i=fread(pFileText,iFileSize,1,m_File.hFile);
//按行分析配置文件内容
pLine=strtok(pFileText,"\n");
while(pLine!=NULL)
{
ltrim(szLineBuff,pLine); //去掉左边的空格
//判断行的类型,0为空节行,1为节行,2为键值对行,3为节注释行(包括空行和错误行),4为键值对注释行(包括空行和错误行)
if(m_File.pNode==NULL) //如果当前指针pNode指向NULL,则为一个空节行
iLineType=0;
else
{
if(szLineBuff[0]=='[')
iLineType=(instr(1,szLineBuff,"]")>0)?1:3;
else
{
if(instr(1,szLineBuff,"=")>0)
iLineType=2;
else
iLineType=(m_File.pNode->iKeys==0)?3:4;
}
}
switch(iLineType)
{
case 0: //空节行
m_File.iNodes=1;
m_File.pNodes=malloc(NODE_SIZE);
m_File.pNode=m_File.pNodes;
m_File.pNode->iKeys=0;
m_File.pNode->pKeys=NULL;
m_File.pNode->Name[0]='\0';
m_File.pNode->pComment=malloc(strlen(pLine)+2);
strcpy(m_File.pNode->pComment,pLine);
break;
case 1: //节行
m_File.iNodes++; //节计数加1
if(m_File.pNode==NULL)
m_File.pNodes=malloc(NODE_SIZE); //申请一个新的节
else
m_File.pNodes=(struct NODE_INFO *)realloc(m_File.pNodes,NODE_SIZE*m_File.iNodes); //重新申请节
m_File.pNode=m_File.pNodes+(m_File.iNodes-1); //将pNode指向当前节
m_File.pNode->iKeys=0;
m_File.pNode->pKeys=NULL;
i=instr(1,szLineBuff,"]");
substr(m_File.pNode->Name,szLineBuff,1,i-1);
//查找有无行尾节注释
i=instr(i+1,szLineBuff,"#");
if(i>0) //如果有
{
m_File.pNode->pComment=malloc(strlen(szLineBuff)-i+2);
strcpy(m_File.pNode->pComment,szLineBuff+i);
}
else
{
m_File.pNode->pComment=malloc(2);
m_File.pNode->pComment[0]='\0';
}
break;
case 2: //键值对行
m_File.pNode->iKeys++;
if(m_File.pNode->pKeys==NULL)
m_File.pNode->pKeys=malloc(KEY_SIZE); //申请一个新的键值对
else
m_File.pNode->pKeys=(struct KEY_INFO *)realloc(m_File.pNode->pKeys,KEY_SIZE*m_File.pNode->iKeys); //重新申请键值对
i=instr(1,pLine,"=");
substr(m_File.pNode->pKeys[m_File.pNode->iKeys-1].Name,pLine,0,i);
//查找有无行尾注释
j=instr(i,pLine,"#");
if(j>0) //如果有
{
substr(m_File.pNode->pKeys[m_File.pNode->iKeys-1].Value,pLine,i+1,j-i-1);
m_File.pNode->pKeys[m_File.pNode->iKeys-1].pComment=malloc(strlen(pLine)-j+2);
strcpy(m_File.pNode->pKeys[m_File.pNode->iKeys-1].pComment,pLine+j);
}
else
{
strcpy(m_File.pNode->pKeys[m_File.pNode->iKeys-1].Value,pLine+i+1);
m_File.pNode->pKeys[m_File.pNode->iKeys-1].pComment=malloc(2);
m_File.pNode->pKeys[m_File.pNode->iKeys-1].pComment[0]='\0';
}
//去掉Key值的左右空格
alltrim(m_File.pNode->pKeys[m_File.pNode->iKeys-1].Value,m_File.pNode->pKeys[m_File.pNode->iKeys-1].Value);
break;
case 3: //节注释行
m_File.pNode->pComment=(LPBYTE )realloc(m_File.pNode->pComment,strlen(m_File.pNode->pComment)+strlen(pLine)+2);
sprintf(m_File.pNode->pComment,"%s\n%s",m_File.pNode->pComment,pLine);
break;
case 4: //键值对注释行
i=m_File.pNode->iKeys-1;
m_File.pNode->pKeys[i].pComment=(LPBYTE )realloc(m_File.pNode->pKeys[i].pComment,strlen(m_File.pNode->pKeys[i].pComment)+strlen(pLine)+2);
sprintf(m_File.pNode->pKeys[i].pComment,"%s\n%s",m_File.pNode->pKeys[i].pComment,pLine);
}
pLine=strtok(NULL,"\n");
}
if(pFileText !=NULL)
free(pFileText);
// fclose(m_File.hFile);
return(&m_File);
}
LPBYTE GetKeyValue(struct FILE_INFO *pFile,char *pNodeName,char *pKeyName)
{
int i,j;
if(strcmp(pFile->pNode->Name,pNodeName)==0) //如果指定的节名称与当前节名称相同
{
for(i=0;ipNode->iKeys;i++)
{
if(strcmp(pFile->pNode->pKeys[i].Name,pKeyName)==0)
return(pFile->pNode->pKeys[i].Value);
}
}
else
{
pFile->pNode=pFile->pNodes;
for(i=0;iiNodes;i++)
{
if(strcmp(pFile->pNode->Name,pNodeName)==0)
{
for(j=0;jpNode->iKeys;j++)
{
if(strcmp(pFile->pNode->pKeys[j].Name,pKeyName)==0)
return(pFile->pNode->pKeys[j].Value);
}
break;
}
pFile->pNode++;
}
}
return(NULL);
}
int CloseIniFile(struct FILE_INFO *pFile) //关闭配置文件
{
int i,j;
if(pFile->pNodes!=NULL)
{
pFile->pNode=pFile->pNodes;
for(i=0;iiNodes;i++)
{
free(pFile->pNode->pComment); //释放节注释
for(j=0;jpNode->iKeys;j++)
free(pFile->pNode->pKeys[j].pComment); //释放键值对注释
free(pFile->pNode->pKeys); //释放键值对
pFile->pNode++;
}
free(pFile->pNodes);
}
fclose(pFile->hFile);
}
#endif
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
文件名称:inifile.h
功能说明:配置文件读写函数库
编者信息:lyserver
联系方式:http://blog.csdn.net/lyserver
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
#ifndef INI_FILE_DEF
#define INI_FILE_DEF
#include
#include
#include
#include "stringex.h"
struct KEY_INFO
{
BYTE Name[64]; //Key名称
BYTE Value[64]; //Key值
LPBYTE pComment; //指向Key注释的指针
};
struct NODE_INFO
{
BYTE Name[64]; //节名称
LPBYTE pComment; //节注释
int iKeys; //键计数
struct KEY_INFO *pKeys; //键数组指针
};
struct FILE_INFO
{
FILE *hFile; //文件句柄
int iNodes; //文件包含的节数
struct NODE_INFO *pNodes; //节数组指针
struct NODE_INFO *pNode; //当前节指针
};
struct FILE_INFO *OpenIniFile(char *pFileName); //打开或创建配置文件
LPBYTE GetKeyValue(struct FILE_INFO *pFile,char *pNodeName,char *pKeyName);
int CloseIniFile(struct FILE_INFO *pFile); //关闭配置文件
struct FILE_INFO *OpenIniFile(char *pFileName) //打开或创建配置文件
{
int i,j; //临时变量,常常用于循环计数
static struct FILE_INFO m_File; //局部静态结构变量
int iFileSize=0,iLineType; //iFileSize:文件大小,iLineType:行类型
int KEY_SIZE=sizeof(struct KEY_INFO);
int NODE_SIZE=sizeof(struct NODE_INFO);
BYTE szLineBuff[256]; //szLineText行内容缓冲区
LPBYTE pFileText=NULL,pLine=NULL; //pFileText:配置文件内容缓冲区,pLine:行内容指针,p:临时字符串指针
m_File.hFile=NULL;
m_File.iNodes=0;
m_File.pNode=NULL;
m_File.pNodes=NULL;
if((m_File.hFile=fopen(pFileName,"r"))==NULL) //如果文件不存在
return(NULL);
//取文件长度
fseek(m_File.hFile,0,SEEK_END);
iFileSize=ftell(m_File.hFile);
if(iFileSize == 0) //如果长度等于0,返回创建的文件指针
return(NULL);
//读配置文件到缓冲区
fseek(m_File.hFile,0,SEEK_SET);
pFileText = (char*)malloc(iFileSize+2); //申请内存,大小为文件长度+2(防止内存溢出)
memset(pFileText,0,iFileSize+1);
i=fread(pFileText,iFileSize,1,m_File.hFile);
//按行分析配置文件内容
pLine=strtok(pFileText,"\n");
while(pLine!=NULL)
{
ltrim(szLineBuff,pLine); //去掉左边的空格
//判断行的类型,0为空节行,1为节行,2为键值对行,3为节注释行(包括空行和错误行),4为键值对注释行(包括空行和错误行)
if(m_File.pNode==NULL) //如果当前指针pNode指向NULL,则为一个空节行
iLineType=0;
else
{
if(szLineBuff[0]=='[')
iLineType=(instr(1,szLineBuff,"]")>0)?1:3;
else
{
if(instr(1,szLineBuff,"=")>0)
iLineType=2;
else
iLineType=(m_File.pNode->iKeys==0)?3:4;
}
}
switch(iLineType)
{
case 0: //空节行
m_File.iNodes=1;
m_File.pNodes=malloc(NODE_SIZE);
m_File.pNode=m_File.pNodes;
m_File.pNode->iKeys=0;
m_File.pNode->pKeys=NULL;
m_File.pNode->Name[0]='\0';
m_File.pNode->pComment=malloc(strlen(pLine)+2);
strcpy(m_File.pNode->pComment,pLine);
break;
case 1: //节行
m_File.iNodes++; //节计数加1
if(m_File.pNode==NULL)
m_File.pNodes=malloc(NODE_SIZE); //申请一个新的节
else
m_File.pNodes=(struct NODE_INFO *)realloc(m_File.pNodes,NODE_SIZE*m_File.iNodes); //重新申请节
m_File.pNode=m_File.pNodes+(m_File.iNodes-1); //将pNode指向当前节
m_File.pNode->iKeys=0;
m_File.pNode->pKeys=NULL;
i=instr(1,szLineBuff,"]");
substr(m_File.pNode->Name,szLineBuff,1,i-1);
//查找有无行尾节注释
i=instr(i+1,szLineBuff,"#");
if(i>0) //如果有
{
m_File.pNode->pComment=malloc(strlen(szLineBuff)-i+2);
strcpy(m_File.pNode->pComment,szLineBuff+i);
}
else
{
m_File.pNode->pComment=malloc(2);
m_File.pNode->pComment[0]='\0';
}
break;
case 2: //键值对行
m_File.pNode->iKeys++;
if(m_File.pNode->pKeys==NULL)
m_File.pNode->pKeys=malloc(KEY_SIZE); //申请一个新的键值对
else
m_File.pNode->pKeys=(struct KEY_INFO *)realloc(m_File.pNode->pKeys,KEY_SIZE*m_File.pNode->iKeys); //重新申请键值对
i=instr(1,pLine,"=");
substr(m_File.pNode->pKeys[m_File.pNode->iKeys-1].Name,pLine,0,i);
//查找有无行尾注释
j=instr(i,pLine,"#");
if(j>0) //如果有
{
substr(m_File.pNode->pKeys[m_File.pNode->iKeys-1].Value,pLine,i+1,j-i-1);
m_File.pNode->pKeys[m_File.pNode->iKeys-1].pComment=malloc(strlen(pLine)-j+2);
strcpy(m_File.pNode->pKeys[m_File.pNode->iKeys-1].pComment,pLine+j);
}
else
{
strcpy(m_File.pNode->pKeys[m_File.pNode->iKeys-1].Value,pLine+i+1);
m_File.pNode->pKeys[m_File.pNode->iKeys-1].pComment=malloc(2);
m_File.pNode->pKeys[m_File.pNode->iKeys-1].pComment[0]='\0';
}
//去掉Key值的左右空格
alltrim(m_File.pNode->pKeys[m_File.pNode->iKeys-1].Value,m_File.pNode->pKeys[m_File.pNode->iKeys-1].Value);
break;
case 3: //节注释行
m_File.pNode->pComment=(LPBYTE )realloc(m_File.pNode->pComment,strlen(m_File.pNode->pComment)+strlen(pLine)+2);
sprintf(m_File.pNode->pComment,"%s\n%s",m_File.pNode->pComment,pLine);
break;
case 4: //键值对注释行
i=m_File.pNode->iKeys-1;
m_File.pNode->pKeys[i].pComment=(LPBYTE )realloc(m_File.pNode->pKeys[i].pComment,strlen(m_File.pNode->pKeys[i].pComment)+strlen(pLine)+2);
sprintf(m_File.pNode->pKeys[i].pComment,"%s\n%s",m_File.pNode->pKeys[i].pComment,pLine);
}
pLine=strtok(NULL,"\n");
}
if(pFileText !=NULL)
free(pFileText);
// fclose(m_File.hFile);
return(&m_File);
}
LPBYTE GetKeyValue(struct FILE_INFO *pFile,char *pNodeName,char *pKeyName)
{
int i,j;
if(strcmp(pFile->pNode->Name,pNodeName)==0) //如果指定的节名称与当前节名称相同
{
for(i=0;i
pNode->iKeys;i++)
{
if(strcmp(pFile->pNode->pKeys[i].Name,pKeyName)==0)
return(pFile->pNode->pKeys[i].Value);
}
}
else
{
pFile->pNode=pFile->pNodes;
for(i=0;iiNodes;i++)
{
if(strcmp(pFile->pNode->Name,pNodeName)==0)
{
for(j=0;jpNode->iKeys;j++)
{
if(strcmp(pFile->pNode->pKeys[j].Name,pKeyName)==0)
return(pFile->pNode->pKeys[j].Value);
}
break;
}
pFile->pNode++;
}
}
return(NULL);
}
int CloseIniFile(struct FILE_INFO *pFile) //关闭配置文件
{
int i,j;
if(pFile->pNodes!=NULL)
{
pFile->pNode=pFile->pNodes;
for(i=0;i
iNodes;i++)
{
free(pFile->pNode->pComment); //释放节注释
for(j=0;jpNode->iKeys;j++)
free(pFile->pNode->pKeys[j].pComment); //释放键值对注释
free(pFile->pNode->pKeys); //释放键值对
pFile->pNode++;
}
free(pFile->pNodes);
}
fclose(pFile->hFile);
}
#endif
三、daemon.h,守护进程函数库:
view plaincopy to clipboardprint?
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
文件名称:daemon.h
功能说明:实现守护进程
编者信息:lyserver
联系方式:http://blog.csdn.net/lyserver
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
#ifndef DAEMON_PROCESS_DEF
#define DAEMON_PROCESS_DEF
#include
#include
#include
#include
#include
#include
void MakeDaemon(char* pLogFileName,int (*pfnMessageLoop)());
char *GetCurrentDateAndTime(); //辅助函数,获取当前日期和时间
void MakeDaemon(char* pLogFileName,int (*pfnMessageLoop)(FILE *hLog))
{
static FILE *fpLog=NULL; //日志文件指针
char szLogInfo[63];
//忽略I/O信号和STOP信号
signal(SIGTTOU,SIG_IGN);
signal(SIGTTIN,SIG_IGN);
signal(SIGTSTP,SIG_IGN);
signal(SIGHUP,SIG_IGN);
//退出父进程,程序转入后台运行
if(fork()!=0)return;
//创建一个新的会议组
if(setsid()<0)return;
//退出子进程,让孙进程失去终端控制
if(fork()!=0)return;
//忽略SIGCHLD信号
signal(SIGCHLD,SIG_IGN);
//处理日志文件
if(pLogFileName!=NULL)
{
if((fpLog=fopen(pLogFileName,"r"))==NULL) //如果文件不存在
fpLog=fopen(pLogFileName,"w");
else
{
fclose(fpLog);
fpLog=fopen(pLogFileName,"a+");
}
}
//写日志信息(服务开始)
if(fpLog!=NULL)
{
sprintf(szLogInfo,"服务从【%s】开始运行...\n",GetCurrentDateAndTime());
fputs(szLogInfo,fpLog);
fflush(fpLog);
}
//调用指定的事件pfnMessageLoop
if((*pfnMessageLoop)!=NULL)
(*pfnMessageLoop)(fpLog);
//写日志信息(服务结束)
if(fpLog!=NULL)
{
sprintf(szLogInfo,"服务在【%s】停止运行!\n",GetCurrentDateAndTime());
fputs(szLogInfo,fpLog);
fflush(fpLog);
fclose(fpLog);
}
}
char *GetCurrentDateAndTime()
{
time_t timep;
struct tm *p;
static char my_date_time[31];
time(&timep);
p=localtime(&timep); //取得当地时间
sprintf(my_date_time,"%d年%d月%d日 %d:%d:%d",(1900+p->tm_year),(1+p->tm_mon),p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec);
return(my_date_time);
}
#endif
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
文件名称:daemon.h
功能说明:实现守护进程
编者信息:lyserver
联系方式:http://blog.csdn.net/lyserver
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
#ifndef DAEMON_PROCESS_DEF
#define DAEMON_PROCESS_DEF
#include
#include
#include
#include
#include
#include
void MakeDaemon(char* pLogFileName,int (*pfnMessageLoop)());
char *GetCurrentDateAndTime(); //辅助函数,获取当前日期和时间
void MakeDaemon(char* pLogFileName,int (*pfnMessageLoop)(FILE *hLog))
{
static FILE *fpLog=NULL; //日志文件指针
char szLogInfo[63];
//忽略I/O信号和STOP信号
signal(SIGTTOU,SIG_IGN);
signal(SIGTTIN,SIG_IGN);
signal(SIGTSTP,SIG_IGN);
signal(SIGHUP,SIG_IGN);
//退出父进程,程序转入后台运行
if(fork()!=0)return;
//创建一个新的会议组
if(setsid()<0)return;
//退出子进程,让孙进程失去终端控制
if(fork()!=0)return;
//忽略SIGCHLD信号
signal(SIGCHLD,SIG_IGN);
//处理日志文件
if(pLogFileName!=NULL)
{
if((fpLog=fopen(pLogFileName,"r"))==NULL) //如果文件不存在
fpLog=fopen(pLogFileName,"w");
else
{
fclose(fpLog);
fpLog=fopen(pLogFileName,"a+");
}
}
//写日志信息(服务开始)
if(fpLog!=NULL)
{
sprintf(szLogInfo,"服务从【%s】开始运行...\n",GetCurrentDateAndTime());
fputs(szLogInfo,fpLog);
fflush(fpLog);
}
//调用指定的事件pfnMessageLoop
if((*pfnMessageLoop)!=NULL)
(*pfnMessageLoop)(fpLog);
//写日志信息(服务结束)
if(fpLog!=NULL)
{
sprintf(szLogInfo,"服务在【%s】停止运行!\n",GetCurrentDateAndTime());
fputs(szLogInfo,fpLog);
fflush(fpLog);
fclose(fpLog);
}
}
char *GetCurrentDateAndTime()
{
time_t timep;
struct tm *p;
static char my_date_time[31];
time(&timep);
p=localtime(&timep); //取得当地时间
sprintf(my_date_time,"%d年%d月%d日 %d:%d:%d",(1900+p->tm_year),(1+p->tm_mon),p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec);
return(my_date_time);
}
#endif
四、asynccom.h,串口通信函数库:
view plaincopy to clipboardprint?
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
文件名称:asynccom.h
功能说明:串口异步通信函数库
编者信息:lyserver
联系方式:http://blog.csdn.net/lyserver
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
#ifndef ASYNC_COM_DEF
#define ASYNC_COM_DEF
#include
#include
#include
#include
#define _POSIX_SOURCE 1 //POSIX 系统相容
int OpenComm(int iCommPort); //打开串口设备文件,iCommPort串口端口号,返回句柄
void CloseComm(int hComm); //关闭设备文件
int SetCommParam(int hComm,int BaudRate,unsigned char ParityBits,int DataBits,int StopBits); //参数设置,包括:波特率,校验位,停止位,数据位
int WriteComm(int hComm,char *pBuff); //写串口
unsigned char *ReadComm(int hComm); //以同步方式读串口
int OpenComm(int iCommPort) //打开串口设备文件,iCommPort串口端口号,返回句柄
{
int hComm;
char szCommFileName[127];
struct sigaction saio;
sprintf(szCommFileName,"/dev/ttyS%d",iCommPort-1);
hComm=open(szCommFileName,O_RDWR|O_NOCTTY|O_NONBLOCK);//加上O_NONBLOCK:非块模式(专用于命名管道),O_NDELAY:非阻塞模式
//在使实现异步访问方式前,安装信号处理函数
saio.sa_handler = signal_handler_IO;
saio.sa_mask = 0;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);
//允许进程去接收SIGIO 信号
fcntl(hComm, F_SETOWN, getpid());
//允许串口设备为异步访问
fcntl(hComm, F_SETFL, FASYNC);
return(hComm);
}
void CloseComm(int hComm) //关闭设备文件
{
tcflush(hComm,TCIOFLUSH); //清空输入输出数据线
usleep(100000); //延时100毫秒
close(hComm);
}
int SetCommParam(int hComm,int BaudRate,unsigned char ParityBits,int DataBits,int StopBits)//参数设置,包括:波特率,校验位,停止位,数据位
{
int i;
struct termios options;
int speed_value[]={B115200,B38400,B19200,B9600,B4800};
int speed_name[]={115200,38400,19200,9600,4800};
tcflush(hComm,TCIOFLUSH);
tcgetattr(hComm,&options);
// bzero(&options,sizeof(struct termios));
options.c_cflag=(CLOCAL|CREAD|CRTSCTS); //Control options
options.c_cflag&=~CSIZE; //Control options
options.c_lflag=ICANON; //Local options
//options.c_oflag&=~OPOST; //Output options
options.c_oflag=0; //Output options,Raw模式
options.c_iflag=(IGNPAR|ICRNL); //Input options
options.c_cc[VTIME]=0;
options.c_cc[VMIN]=1;
options.c_cc[VEOF]=4;
// options.c_iflag&=~(IXON|IXOFF|IXANY); //Input options
/*以下为Control characters
options.c_cc[VINTR]=0;//Ctrl-c
options.c_cc[VQUIT]=0;//Ctrl-
options.c_cc[VERASE]=0;//del
options.c_cc[VKILL]=0;//@
options.c_cc[VEOF]=4;//Ctrl-d
options.c_cc[VTIME]=0;//不使用分割字元组的计时器
options.c_cc[VMIN]=1;//在读取到 1 个字元前先停止
options.c_cc[VSWTC]=0;//'\0'
options.c_cc[VSTART]=0; //Ctrl-q
options.c_cc[VSTOP]=0; //Ctrl-s
options.c_cc[VSUSP]=26; //Ctrl-z
options.c_cc[VEOL]=0; //'\0'
options.c_cc[VREPRINT]=0; //Ctrl-r
options.c_cc[VDISCARD]=0; //Ctrl-u
options.c_cc[VWERASE]=0; //Ctrl-w
options.c_cc[VLNEXT]=0; //Ctrl-v
options.c_cc[VEOL2]=0; //'\0'*/
//设置波特率
for(i=0;i {
if(BaudRate==speed_name[i])
{
options.c_cflag|=speed_value[i];
break;
}
}
//设置校验位
switch(ParityBits)
{
case 'o':case 'O': //奇校验
options.c_cflag|=(PARODD|PARENB);
options.c_iflag|=INPCK;
break;
case 'e':case 'E': //偶校验
options.c_cflag|=PARENB;
options.c_cflag&=~PARODD;
options.c_iflag|=INPCK;
break;
case 's':case 'S': //Space校验
options.c_cflag&=~PARENB;
options.c_cflag&=~CSTOPB;
options.c_iflag|=INPCK;
break;
default: //默认为无校验,即'n'或'N'
options.c_cflag&=~PARENB;
options.c_iflag&=~INPCK;
}
//设置数据位
if(DataBits==7)
options.c_cflag|=CS7;
else
options.c_cflag|=CS8;
//设置停止位
if(StopBits==1)
options.c_cflag&=~CSTOPB;
else
options.c_cflag|=CSTOPB;
//清空数据线,并启用新的设置
tcflush(hComm,TCIFLUSH);
tcsetattr(hComm,TCSANOW,&options);
}
int WriteComm(int hComm,char *pBuff) //写串口
{
int iBytes=0;
iBytes=write(hComm,pBuff,strlen(pBuff));
return(iBytes);
}
unsigned char *ReadComm(int hComm) //以同步方式读串口
{
int iBytes;
static unsigned char szBuff[256]; //数据缓存
memset(szBuff,0,256);
iBytes=read(hComm,szBuff,256);
return(szBuff);
}
#endif
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
文件名称:asynccom.h
功能说明:串口异步通信函数库
编者信息:lyserver
联系方式:http://blog.csdn.net/lyserver
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
#ifndef ASYNC_COM_DEF
#define ASYNC_COM_DEF
#include
#include
#include
#include
#define _POSIX_SOURCE 1 //POSIX 系统相容
int OpenComm(int iCommPort); //打开串口设备文件,iCommPort串口端口号,返回句柄
void CloseComm(int hComm); //关闭设备文件
int SetCommParam(int hComm,int BaudRate,unsigned char ParityBits,int DataBits,int StopBits); //参数设置,包括:波特率,校验位,停止位,数据位
int WriteComm(int hComm,char *pBuff); //写串口
unsigned char *ReadComm(int hComm); //以同步方式读串口
int OpenComm(int iCommPort) //打开串口设备文件,iCommPort串口端口号,返回句柄
{
int hComm;
char szCommFileName[127];
struct sigaction saio;
sprintf(szCommFileName,"/dev/ttyS%d",iCommPort-1);
hComm=open(szCommFileName,O_RDWR|O_NOCTTY|O_NONBLOCK);//加上O_NONBLOCK:非块模式(专用于命名管道),O_NDELAY:非阻塞模式
//在使实现异步访问方式前,安装信号处理函数
saio.sa_handler = signal_handler_IO;
saio.sa_mask = 0;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);
//允许进程去接收SIGIO 信号
fcntl(hComm, F_SETOWN, getpid());
//允许串口设备为异步访问
fcntl(hComm, F_SETFL, FASYNC);
return(hComm);
}
void CloseComm(int hComm) //关闭设备文件
{
tcflush(hComm,TCIOFLUSH); //清空输入输出数据线
usleep(100000); //延时100毫秒
close(hComm);
}
int SetCommParam(int hComm,int BaudRate,unsigned char ParityBits,int DataBits,int StopBits)//参数设置,包括:波特率,校验位,停止位,数据位
{
int i;
struct termios options;
int speed_value[]={B115200,B38400,B19200,B9600,B4800};
int speed_name[]={115200,38400,19200,9600,4800};
tcflush(hComm,TCIOFLUSH);
tcgetattr(hComm,&options);
// bzero(&options,sizeof(struct termios));
options.c_cflag=(CLOCAL|CREAD|CRTSCTS); //Control options
options.c_cflag&=~CSIZE; //Control options
options.c_lflag=ICANON; //Local options
//options.c_oflag&=~OPOST; //Output options
options.c_oflag=0; //Output options,Raw模式
options.c_iflag=(IGNPAR|ICRNL); //Input options
options.c_cc[VTIME]=0;
options.c_cc[VMIN]=1;
options.c_cc[VEOF]=4;
// options.c_iflag&=~(IXON|IXOFF|IXANY); //Input options
/*以下为Control characters
options.c_cc[VINTR]=0;//Ctrl-c
options.c_cc[VQUIT]=0;//Ctrl-
options.c_cc[VERASE]=0;//del
options.c_cc[VKILL]=0;//@
options.c_cc[VEOF]=4;//Ctrl-d
options.c_cc[VTIME]=0;//不使用分割字元组的计时器
options.c_cc[VMIN]=1;//在读取到 1 个字元前先停止
options.c_cc[VSWTC]=0;//'\0'
options.c_cc[VSTART]=0; //Ctrl-q
options.c_cc[VSTOP]=0; //Ctrl-s
options.c_cc[VSUSP]=26; //Ctrl-z
options.c_cc[VEOL]=0; //'\0'
options.c_cc[VREPRINT]=0; //Ctrl-r
options.c_cc[VDISCARD]=0; //Ctrl-u
options.c_cc[VWERASE]=0; //Ctrl-w
options.c_cc[VLNEXT]=0; //Ctrl-v
options.c_cc[VEOL2]=0; //'\0'*/
//设置波特率
for(i=0;i {
if(BaudRate==speed_name[i])
{
options.c_cflag|=speed_value[i];
break;
}
}
//设置校验位
switch(ParityBits)
{
case 'o':case 'O': //奇校验
options.c_cflag|=(PARODD|PARENB);
options.c_iflag|=INPCK;
break;
case 'e':case 'E': //偶校验
options.c_cflag|=PARENB;
options.c_cflag&=~PARODD;
options.c_iflag|=INPCK;
break;
case 's':case 'S': //Space校验
options.c_cflag&=~PARENB;
options.c_cflag&=~CSTOPB;
options.c_iflag|=INPCK;
break;
default: //默认为无校验,即'n'或'N'
options.c_cflag&=~PARENB;
options.c_iflag&=~INPCK;
}
//设置数据位
if(DataBits==7)
options.c_cflag|=CS7;
else
options.c_cflag|=CS8;
//设置停止位
if(StopBits==1)
options.c_cflag&=~CSTOPB;
else
options.c_cflag|=CSTOPB;
//清空数据线,并启用新的设置
tcflush(hComm,TCIFLUSH);
tcsetattr(hComm,TCSANOW,&options);
}
int WriteComm(int hComm,char *pBuff) //写串口
{
int iBytes=0;
iBytes=write(hComm,pBuff,strlen(pBuff));
return(iBytes);
}
unsigned char *ReadComm(int hComm) //以同步方式读串口
{
int iBytes;
static unsigned char szBuff[256]; //数据缓存
memset(szBuff,0,256);
iBytes=read(hComm,szBuff,256);
return(szBuff);
}
#endif
五、sms.h,基于短信猫的短信收发函数库:
view plaincopy to clipboardprint?
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
文件名称:sms.h
功能说明:SMS短信收发函数库
编者信息:lyserver
联系方式:http://blog.csdn.net/lyserver
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
#ifndef SMS_INFO_DEF
#define SMS_INFO_DEF
#include "stringex.h" //必须包含此头文件
#include "synccom.h" //必需包含此头文件
//BYTE SSTR_SMS_CODE,SSTR_AREA_CODE; //短信中心号码,小灵通区号
struct SMS_INFO
{
int hComm; //短信设备句柄
int iDelayTime; //等待延时
BYTE SMS_CODE[16]; //短信中心号码
BYTE SMS_CODE_PDU[16];//PDU编码的短信中心号码,需要调用者转换
BYTE SMS_CODE_TYPE; //短信中心号码类型,0:移动,1:联通,2:小灵通
BYTE AREA_CODE[4]; //小灵通区号,由于要在TEL2PDU辅助函数中用,需要调用者赋值
};
struct SMS_INFO *OpenModem(int iCommPort,int iBaudRate,int iRetry); //初始化短信猫设备
void CloseModem(struct SMS_INFO *pSms); //关闭短信猫设备
int SendMessage(struct SMS_INFO *pSms,LPBYTE pUserCode,LPBYTE pMessage); //发送短信,pUserCode:接收手机号码,pMessage:短信内容,可递归调用
int WriteModem(int hComm,char *pMessage,int iRetry); //辅助函数,向短信猫写数据
int ReadModem(int hComm,int iRetry); //辅助函数,读短信猫的反馈信息,-1:错误,0:超时,1:正确
void TEL2PDU(LPBYTE pSrcCode,LPBYTE pDstCode,LPBYTE pAreaCode); //辅助函数,电话号码转PDU编码字符串
void PDU2TEL(LPBYTE pSrcCode,LPBYTE pDstCode); //辅助函数,PDU编码字符串转电话号码
struct SMS_INFO *OpenModem(int iCommPort,int iBaudRate,int iRetry) //初始化短信猫设备,iCommPort:串口号,iRetry:重试次数
{
int i;
static struct SMS_INFO m_Sms;
m_Sms.hComm=OpenComm(iCommPort); //打开短信猫所连的串口
if(m_Sms.hComm<1)return(NULL);
SetCommParam(m_Sms.hComm,iBaudRate,'N',8,1); //设置串口通讯参数
m_Sms.SMS_CODE[0]='\0';
m_Sms.AREA_CODE[0]='\0';
m_Sms.SMS_CODE_TYPE='0';
m_Sms.iDelayTime=0;
m_Sms.SMS_CODE_PDU[0]='\0';
//初始化短信猫设备
for(i=0;i {
WriteComm(m_Sms.hComm,"AT\r");
if((ReadModem(m_Sms.hComm,10))==1)
{
WriteComm(m_Sms.hComm,"ATE0\r");
if((ReadModem(m_Sms.hComm,10))==1) //成功初始化
{
//设置是否接收短信通知
WriteComm(m_Sms.hComm,"AT+CNMI=0,0,0,0,1\r");
if((ReadModem(m_Sms.hComm,10))==1) //0,0,0,0,1(不通知),1,1,0,2,1(通知)
{
printf("短信猫初始化成功!\n");
return(&m_Sms);
}
}
}
printf("第%d次初始化短信猫失败!\n",i+1);
}
CloseComm(m_Sms.hComm); //当指定的次数内不能完成初始化时,关闭串口
return(NULL);
}
void CloseModem(struct SMS_INFO *pSms)
{
if(pSms!=NULL)
CloseComm(pSms->hComm);
}
int SendMessage(struct SMS_INFO *pSms,LPBYTE pUserCode,LPBYTE pMessage) //发送短信,pUserCode:接收手机号码,pMessage:短信内容,可递归调用
/*数据包结构说明:
1-2位:(短信中心号码长度+2(即3-4位长度))/2(16进制)
3-4位:短信中心号码有无国家编码(91有,81无)
X位:短信中心号码(需PDU编码),以下为X位后
1-2位:状态报告(31有,11无) *注意:从此处开始计算数据包长度
3-4位:分隔符(永远为00)
5-6位:目标号码长度(16进制)
7-8位:目标号码有无国家编码(91有,81无)
XX为:目标号码(需PDU编码),以下为XX位后
1-2位:TP-PID协议(一般为00)
3-4为:是否免提(18是,08否)
5-6位:有效期标志(一般为00)
7-8位:短信实际长度(16进制)
XXX位:短信内容,以下为XXX位后
1位:结束符(ASCII码26)
*/
{
static unsigned char bIsHex=0; //HEX编码标志,0:未经过编码,1:已编码
int iRetval=0; //返回值,0表示失败,1表示成功
int iPacketLen; //数据包长度,从第19个字符开始计算(需除2)
int iTextLen=strlen(pMessage); //实际短信内容长度(需除2)
BYTE szBuff[64]; //临时变量
BYTE szText[300]; //短信内容,,一条短信最多70个字符(即140个HEX字符)
BYTE szTextHEX[1024]; //经过HEX编码的短信内容
BYTE szPacket[512]; //短信数据包
BYTE szUserCodePDU[20]; //经过PDU编码的接收手机号码
if(iTextLen==0) //如果pMessage长度为0,则直接返回
{
bIsHex=0; //重置HEX编码标志
return(0); //如果待发短信内容的长度为0,则直接返回
}
if(bIsHex==0) //如果参数pMessage没有经过HEX编码,则进行HEX编码
{
bIsHex=1; //置标志为已编码状态
str2hex(szTextHEX,pMessage); //将pMessage进行HEX编码,并放入szTextHEX变量
TEL2PDU(pUserCode,szUserCodePDU,pSms->AREA_CODE); //将接收手机号进行PDU编码
iTextLen=strlen(szTextHEX);
}else //否则
{
strcpy(szTextHEX,pMessage);
strcpy(szUserCodePDU,pUserCode);
}
//取前70个字符(即280个HEX编码字符)
iTextLen=(iTextLen>280)?280:iTextLen;
strncpy(szText,szTextHEX,iTextLen);
szText[iTextLen]='\0';
memset(szPacket,0,512); //清空数据包缓冲区
/* **********************************封装数据包***************************** */
iTextLen=(strlen(pSms->SMS_CODE_PDU)+2)/2; //数据包的第一个长度字段,即(中心号码长度+2位国家编码长度)/2
sprintf(szPacket,(iTextLen>15)?"%2X":"0%1X",iTextLen);
sprintf(szPacket,"%s%d",szPacket,((pSms->SMS_CODE_PDU[0]=='6')&&(pSms->SMS_CODE_PDU[1]=='8'))?91:81); //中心号码有无国家编码
sprintf(szPacket,"%s%s",szPacket,pSms->SMS_CODE_PDU); //中心号码
iPacketLen=strlen(szPacket); //从此处开始计算数据包长度(即短信中心号码以后的字符串长度的1/2)
sprintf(szPacket,"%s3100",szPacket); //状态报告、分隔符
iTextLen=strlen(szUserCodePDU)-1; //去掉最后一个'F'
sprintf(szPacket,(iTextLen>15)?"%s%2X":"%s0%1X",szPacket,iTextLen); //目标号码长度
sprintf(szPacket,"%s%d",szPacket,((szUserCodePDU[0]=='6')&&(szUserCodePDU[1]=='8'))?91:81); //目标号码有无国家编码
sprintf(szPacket,"%s%s",szPacket,szUserCodePDU); //目标号码
sprintf(szPacket,"%s000800",szPacket); //TP-PID协议、免提标志、有效期
iTextLen=strlen(szText)/2; //短信内容实际长度
sprintf(szPacket,(iTextLen>15)?"%s%2X":"%s0%1X",szPacket,iTextLen);
sprintf(szPacket,"%s%s%c",szPacket,szText,26); //短信内容及结束符(结束符为1A1D,也有为ASCII码26的)
/* ***********************************封装结束****************************** */
//计算数据包长度
iPacketLen=strlen(szPacket+iPacketLen)/2;
//向GSM MODEM发送控制符,通知以PDU模式发送短信
if((WriteModem(pSms->hComm,"AT+CMGF=0\r",3))==1)
{
//发送数据包长度(尝试5次)
sprintf(szBuff,"AT+CMGS=%d\r",iPacketLen);
WriteComm(pSms->hComm,szBuff);
if((ReadModem(pSms->hComm,50))==1)
{
usleep(100000);
WriteComm(pSms->hComm,szPacket); //发送短信数据包
iRetval=(ReadModem(pSms->hComm,80));
}
}
//根据短信中心号码类型进行延时,以等待短信发送成功
sleep(pSms->iDelayTime);
//如果还有未发的短信内容,则进入递归调用
if(strlen(szTextHEX)>280)
SendMessage(pSms,szUserCodePDU,(LPBYTE)(szTextHEX+280));
bIsHex=0; //重置标志
return(iRetval);
}
int WriteModem(int hComm,char *pMessage,int iRetry) //辅助函数,向短信猫写数据
{
int i,res;
for(i=0;i {
WriteComm(hComm,pMessage);
res=ReadModem(hComm,10);
if(res==1)
return(1);
}
return(0);
}
int ReadModem(int hComm,int iRetry) //辅助函数,度短信猫的反馈信息,-1:错误,0:超时,1:正确
{
int i;
char *p;
for(i=0;i {
usleep(50000); //延时50毫秒
p=ReadComm(hComm);
if((strcmp(p,"OK")>=0)||(strcmp(p,">")>=0))
return(1);
else if(strcmp(p,"ERROR")>=0)
return(-1);
}
return(0);
}
void TEL2PDU(LPBYTE pSrcCode,LPBYTE pDstCode,LPBYTE pAreaCode) //辅助函数,电话号码转PDU字符串
{
int i,l;
BYTE szBuff[16];//临时变量
//根据是否有区号判断号码是否为小灵通
if(pSrcCode[0]=='0') //如果是,则加上106前缀
sprintf(szBuff,"106%s",pSrcCode);
else
{
//根据长度是否小于11位判断是否为小灵通
l=strlen(pSrcCode);
if(l<11) //如果长度小于11位,则为未加区号的小灵通
sprintf(szBuff,"106%s%s",pAreaCode,pSrcCode);
else //否则为手机号码
{
if((pSrcCode[0]!='8')||(pSrcCode[1]!='6'))
sprintf(szBuff,"86%s",pSrcCode);
else
strcpy(szBuff,pSrcCode);
}
}
//判断加上前缀后的号码长度是否为奇数,如果是,则在最后补"F"字符
l=strlen(szBuff)+1;
if((l % 2)==0)
sprintf(szBuff,"%sF",szBuff);
//对号码进行PDU编码,即奇偶对调
for(i=0;i {
pDstCode[i]=szBuff[i+1];
pDstCode[i+1]=szBuff[i];
}
pDstCode[l]='\0';
}
void PDU2TEL(LPBYTE pSrcCode,LPBYTE pDstCode) //辅助函数,PDU字符串转电话号码
{
int i;
BYTE szBuff[16]; //临时变量
memset(szBuff,0,16);
//奇偶对调
for(i=0;i {
szBuff[i]=pSrcCode[i+1];
szBuff[i+1]=pSrcCode[i];
}
//截去后缀字符F(如果有)
i=strlen(szBuff);
if(szBuff[i-1]=='F')szBuff[i-1]='\0';
strcpy(pDstCode,szBuff);
}
#endif
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
文件名称:sms.h
功能说明:SMS短信收发函数库
编者信息:lyserver
联系方式:http://blog.csdn.net/lyserver
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
#ifndef SMS_INFO_DEF
#define SMS_INFO_DEF
#include "stringex.h" //必须包含此头文件
#include "synccom.h" //必需包含此头文件
//BYTE SSTR_SMS_CODE,SSTR_AREA_CODE; //短信中心号码,小灵通区号
struct SMS_INFO
{
int hComm; //短信设备句柄
int iDelayTime; //等待延时
BYTE SMS_CODE[16]; //短信中心号码
BYTE SMS_CODE_PDU[16];//PDU编码的短信中心号码,需要调用者转换
BYTE SMS_CODE_TYPE; //短信中心号码类型,0:移动,1:联通,2:小灵通
BYTE AREA_CODE[4]; //小灵通区号,由于要在TEL2PDU辅助函数中用,需要调用者赋值
};
struct SMS_INFO *OpenModem(int iCommPort,int iBaudRate,int iRetry); //初始化短信猫设备
void CloseModem(struct SMS_INFO *pSms); //关闭短信猫设备
int SendMessage(struct SMS_INFO *pSms,LPBYTE pUserCode,LPBYTE pMessage); //发送短信,pUserCode:接收手机号码,pMessage:短信内容,可递归调用
int WriteModem(int hComm,char *pMessage,int iRetry); //辅助函数,向短信猫写数据
int ReadModem(int hComm,int iRetry); //辅助函数,读短信猫的反馈信息,-1:错误,0:超时,1:正确
void TEL2PDU(LPBYTE pSrcCode,LPBYTE pDstCode,LPBYTE pAreaCode); //辅助函数,电话号码转PDU编码字符串
void PDU2TEL(LPBYTE pSrcCode,LPBYTE pDstCode); //辅助函数,PDU编码字符串转电话号码
struct SMS_INFO *OpenModem(int iCommPort,int iBaudRate,int iRetry) //初始化短信猫设备,iCommPort:串口号,iRetry:重试次数
{
int i;
static struct SMS_INFO m_Sms;
m_Sms.hComm=OpenComm(iCommPort); //打开短信猫所连的串口
if(m_Sms.hComm<1)return(NULL);
SetCommParam(m_Sms.hComm,iBaudRate,'N',8,1); //设置串口通讯参数
m_Sms.SMS_CODE[0]='\0';
m_Sms.AREA_CODE[0]='\0';
m_Sms.SMS_CODE_TYPE='0';
m_Sms.iDelayTime=0;
m_Sms.SMS_CODE_PDU[0]='\0';
//初始化短信猫设备
for(i=0;i {
WriteComm(m_Sms.hComm,"AT\r");
if((ReadModem(m_Sms.hComm,10))==1)
{
WriteComm(m_Sms.hComm,"ATE0\r");
if((ReadModem(m_Sms.hComm,10))==1) //成功初始化
{
//设置是否接收短信通知
WriteComm(m_Sms.hComm,"AT+CNMI=0,0,0,0,1\r");
if((ReadModem(m_Sms.hComm,10))==1) //0,0,0,0,1(不通知),1,1,0,2,1(通知)
{
printf("短信猫初始化成功!\n");
return(&m_Sms);
}
}
}
printf("第%d次初始化短信猫失败!\n",i+1);
}
CloseComm(m_Sms.hComm); //当指定的次数内不能完成初始化时,关闭串口
return(NULL);
}
void CloseModem(struct SMS_INFO *pSms)
{
if(pSms!=NULL)
CloseComm(pSms->hComm);
}
int SendMessage(struct SMS_INFO *pSms,LPBYTE pUserCode,LPBYTE pMessage) //发送短信,pUserCode:接收手机号码,pMessage:短信内容,可递归调用
/*数据包结构说明:
1-2位:(短信中心号码长度+2(即3-4位长度))/2(16进制)
3-4位:短信中心号码有无国家编码(91有,81无)
X位:短信中心号码(需PDU编码),以下为X位后
1-2位:状态报告(31有,11无) *注意:从此处开始计算数据包长度
3-4位:分隔符(永远为00)
5-6位:目标号码长度(16进制)
7-8位:目标号码有无国家编码(91有,81无)
XX为:目标号码(需PDU编码),以下为XX位后
1-2位:TP-PID协议(一般为00)
3-4为:是否免提(18是,08否)
5-6位:有效期标志(一般为00)
7-8位:短信实际长度(16进制)
XXX位:短信内容,以下为XXX位后
1位:结束符(ASCII码26)
*/
{
static unsigned char bIsHex=0; //HEX编码标志,0:未经过编码,1:已编码
int iRetval=0; //返回值,0表示失败,1表示成功
int iPacketLen; //数据包长度,从第19个字符开始计算(需除2)
int iTextLen=strlen(pMessage); //实际短信内容长度(需除2)
BYTE szBuff[64]; //临时变量
BYTE szText[300]; //短信内容,,一条短信最多70个字符(即140个HEX字符)
BYTE szTextHEX[1024]; //经过HEX编码的短信内容
BYTE szPacket[512]; //短信数据包
BYTE szUserCodePDU[20]; //经过PDU编码的接收手机号码
if(iTextLen==0) //如果pMessage长度为0,则直接返回
{
bIsHex=0; //重置HEX编码标志
return(0); //如果待发短信内容的长度为0,则直接返回
}
if(bIsHex==0) //如果参数pMessage没有经过HEX编码,则进行HEX编码
{
bIsHex=1; //置标志为已编码状态
str2hex(szTextHEX,pMessage); //将pMessage进行HEX编码,并放入szTextHEX变量
TEL2PDU(pUserCode,szUserCodePDU,pSms->AREA_CODE); //将接收手机号进行PDU编码
iTextLen=strlen(szTextHEX);
}else //否则
{
strcpy(szTextHEX,pMessage);
strcpy(szUserCodePDU,pUserCode);
}
//取前70个字符(即280个HEX编码字符)
iTextLen=(iTextLen>280)?280:iTextLen;
strncpy(szText,szTextHEX,iTextLen);
szText[iTextLen]='\0';
memset(szPacket,0,512); //清空数据包缓冲区
/* **********************************封装数据包***************************** */
iTextLen=(strlen(pSms->SMS_CODE_PDU)+2)/2; //数据包的第一个长度字段,即(中心号码长度+2位国家编码长度)/2
sprintf(szPacket,(iTextLen>15)?"%2X":"0%1X",iTextLen);
sprintf(szPacket,"%s%d",szPacket,((pSms->SMS_CODE_PDU[0]=='6')&&(pSms->SMS_CODE_PDU[1]=='8'))?91:81); //中心号码有无国家编码
sprintf(szPacket,"%s%s",szPacket,pSms->SMS_CODE_PDU); //中心号码
iPacketLen=strlen(szPacket); //从此处开始计算数据包长度(即短信中心号码以后的字符串长度的1/2)
sprintf(szPacket,"%s3100",szPacket); //状态报告、分隔符
iTextLen=strlen(szUserCodePDU)-1; //去掉最后一个'F'
sprintf(szPacket,(iTextLen>15)?"%s%2X":"%s0%1X",szPacket,iTextLen); //目标号码长度
sprintf(szPacket,"%s%d",szPacket,((szUserCodePDU[0]=='6')&&(szUserCodePDU[1]=='8'))?91:81); //目标号码有无国家编码
sprintf(szPacket,"%s%s",szPacket,szUserCodePDU); //目标号码
sprintf(szPacket,"%s000800",szPacket); //TP-PID协议、免提标志、有效期
iTextLen=strlen(szText)/2; //短信内容实际长度
sprintf(szPacket,(iTextLen>15)?"%s%2X":"%s0%1X",szPacket,iTextLen);
sprintf(szPacket,"%s%s%c",szPacket,szText,26); //短信内容及结束符(结束符为1A1D,也有为ASCII码26的)
/* ***********************************封装结束****************************** */
//计算数据包长度
iPacketLen=strlen(szPacket+iPacketLen)/2;
//向GSM MODEM发送控制符,通知以PDU模式发送短信
if((WriteModem(pSms->hComm,"AT+CMGF=0\r",3))==1)
{
//发送数据包长度(尝试5次)
sprintf(szBuff,"AT+CMGS=%d\r",iPacketLen);
WriteComm(pSms->hComm,szBuff);
if((ReadModem(pSms->hComm,50))==1)
{
usleep(100000);
WriteComm(pSms->hComm,szPacket); //发送短信数据包
iRetval=(ReadModem(pSms->hComm,80));
}
}
//根据短信中心号码类型进行延时,以等待短信发送成功
sleep(pSms->iDelayTime);
//如果还有未发的短信内容,则进入递归调用
if(strlen(szTextHEX)>280)
SendMessage(pSms,szUserCodePDU,(LPBYTE)(szTextHEX+280));
bIsHex=0; //重置标志
return(iRetval);
}
int WriteModem(int hComm,char *pMessage,int iRetry) //辅助函数,向短信猫写数据
{
int i,res;
for(i=0;i {
WriteComm(hComm,pMessage);
res=ReadModem(hComm,10);
if(res==1)
return(1);
}
return(0);
}
int ReadModem(int hComm,int iRetry) //辅助函数,度短信猫的反馈信息,-1:错误,0:超时,1:正确
{
int i;
char *p;
for(i=0;i {
usleep(50000); //延时50毫秒
p=ReadComm(hComm);
if((strcmp(p,"OK")>=0)||(strcmp(p,">")>=0))
return(1);
else if(strcmp(p,"ERROR")>=0)
return(-1);
}
return(0);
}
void TEL2PDU(LPBYTE pSrcCode,LPBYTE pDstCode,LPBYTE pAreaCode) //辅助函数,电话号码转PDU字符串
{
int i,l;
BYTE szBuff[16];//临时变量
//根据是否有区号判断号码是否为小灵通
if(pSrcCode[0]=='0') //如果是,则加上106前缀
sprintf(szBuff,"106%s",pSrcCode);
else
{
//根据长度是否小于11位判断是否为小灵通
l=strlen(pSrcCode);
if(l<11) //如果长度小于11位,则为未加区号的小灵通
sprintf(szBuff,"106%s%s",pAreaCode,pSrcCode);
else //否则为手机号码
{
if((pSrcCode[0]!='8')||(pSrcCode[1]!='6'))
sprintf(szBuff,"86%s",pSrcCode);
else
strcpy(szBuff,pSrcCode);
}
}
//判断加上前缀后的号码长度是否为奇数,如果是,则在最后补"F"字符
l=strlen(szBuff)+1;
if((l % 2)==0)
sprintf(szBuff,"%sF",szBuff);
//对号码进行PDU编码,即奇偶对调
for(i=0;i {
pDstCode[i]=szBuff[i+1];
pDstCode[i+1]=szBuff[i];
}
pDstCode[l]='\0';
}
void PDU2TEL(LPBYTE pSrcCode,LPBYTE pDstCode) //辅助函数,PDU字符串转电话号码
{
int i;
BYTE szBuff[16]; //临时变量
memset(szBuff,0,16);
//奇偶对调
for(i=0;i {
szBuff[i]=pSrcCode[i+1];
szBuff[i+1]=pSrcCode[i];
}
//截去后缀字符F(如果有)
i=strlen(szBuff);
if(szBuff[i-1]=='F')szBuff[i-1]='\0';
strcpy(pDstCode,szBuff);
}
#endif
六、gsmd.c,短信收发主程序:
view plaincopy to clipboardprint?
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
文件名称:gsmd.c
功能说明:短信发送程序入口
编者信息:lyserver
联系方式:http://blog.csdn.net/lyserver
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
#include "daemon.h"
#include "sms.h"
#include "inifile.h"
#include "stringex.h"
#include "/usr/include/mysql/mysql.h"
/*全局变量*/
struct SMS_INFO *hModem; //短信猫设备变量
char szServer[32]; //数据库服务器名称
char szDatabase[24]; //数据库名称
char szUserName[12]; //数据库用户名
char szPassword[12]; //数据库密码
long lRunTime; //事件发生次数
int iIntervalTime; //事件间隔时间
int MessageLoop(FILE *hLog); //函数声明,主程序代码片段
int main(int argc,char *argv[]) //程序入口
{
FILE *hLog;
int iCommPort=1,iBaudRate=19200; //串口设置变量,iCommPort:串口号,iBaudRate:波特率,iDelayTime:延时
int iDelayTime=4;
char szAreaCode[5],szSmsCode[16],chSmsType; //短信号码设置变量,szAreaCode:小灵通区号,szSmsCode:短信中心号码,chSmsType:短信中心号码类型
struct FILE_INFO *hFile; //配置文件变量
//读取参数配置文件
hFile=OpenIniFile("gsmd.conf");
if(hFile==NULL)return(1);
strcpy(szSmsCode,GetKeyValue(hFile,"MOBILE_CODE","SMS_CODE"));
chSmsType=GetKeyValue(hFile,"MOBILE_CODE","SMS_CODE")[0];
strcpy(szAreaCode,GetKeyValue(hFile,"MOBILE_CODE","AREA_CODE"));
iCommPort=atol(GetKeyValue(hFile,"COMM_SETTING","COMM_PORT"));
iBaudRate=atol(GetKeyValue(hFile,"COMM_SETTING","BAUD_RATE"));
strcpy(szServer,GetKeyValue(hFile,"DATABASE","SERVER"));
strcpy(szDatabase,GetKeyValue(hFile,"DATABASE","DATABASE"));
strcpy(szUserName,GetKeyValue(hFile,"DATABASE","USERNAME"));
strcpy(szPassword,GetKeyValue(hFile,"DATABASE","PASSWORD"));
lRunTime=atol(GetKeyValue(hFile,"EVENT","RUN_TIME"));
iDelayTime=atol(GetKeyValue(hFile,"EVENT","DELAY_TIME"));
iIntervalTime=atol(GetKeyValue(hFile,"EVENT","INTERVAL_TIME"));
//关闭配置文件
CloseIniFile(hFile);
//打开短信猫设备
hModem=OpenModem(iCommPort,iBaudRate,1000);
if(hModem==NULL)return(2);
printf("SMS短信服务程序已成功启动......\n");
//对短信猫设备变量进行一些设置
strncpy(hModem->AREA_CODE,szAreaCode,4); //设置区号
hModem->AREA_CODE[4]='\0';
strcpy(hModem->SMS_CODE,szSmsCode);
hModem->SMS_CODE_TYPE=chSmsType;
hModem->iDelayTime=iDelayTime;
TEL2PDU(hModem->SMS_CODE,hModem->SMS_CODE_PDU,hModem->AREA_CODE); //对短信中心号码进行PDU编码
//将程序转为后台运行
//MakeDaemon("gsmd.log",&MessageLoop);
MessageLoop(NULL);
//关闭短信猫
CloseModem(hModem);
printf("SMS短信服务程序已停止运行!\n");
return(0);
}
int MessageLoop(FILE *hLog) //函数声明,主程序代码片段
{
long lEvent=0;
int col_num,row_num;
MYSQL my_cn;
MYSQL_RES *res_ptr;
MYSQL_ROW my_row;
char szSQL[256];
//打开数据库
mysql_init(&my_cn);
if(mysql_real_connect(&my_cn,szServer,szUserName,szPassword,szDatabase,0,NULL,CLIENT_FOUND_ROWS)==NULL)
return(-1);
//循环查询是否有等待发送的短信
while(1)
{
strcpy(szSQL,"select DEST_TERMINAL_ID,MSG_CONTENT,ROW_ID from submit_msg_base ");
strcat(szSQL,"where instr('130131132133134155156135',left(DEST_TERMINAL_ID,3))>0 ");
strcat(szSQL,"and (ROW_ID Not In (select ROW_ID from submit_msg_status_sending))");
if(mysql_query(&my_cn,szSQL)) //如果有查询结果
{
res_ptr=mysql_store_result(&my_cn);
if(res_ptr)
{
row_num=mysql_num_rows(res_ptr);
col_num=mysql_num_fields(res_ptr);
if(row_num>0)
{
while((my_row=mysql_fetch_row(res_ptr)))
{
//将未发短信放入正在发送的表中
sprintf(szSQL,"insert into submit_msg_status_sending(ROW_ID) values(%s)",my_row[2]);
mysql_query(&my_cn,szSQL);
//发送短信
if((SendMessage(hModem,my_row[0],my_row[1]))==1) //发送成功
{
//写日志
if(hLog!=NULL){
sprintf(szSQL,"ROW_ID为%d的短信于%d成功发送。\n",my_row[2],GetCurrentDateAndTime());
fputs(szSQL,hLog);
fflush(hLog);}
//将已发短信放入已发送的表中
sprintf(szSQL,"insert into submit_msg_status_sended(ROW_ID) values(%s)",my_row[2]);
mysql_query(&my_cn,szSQL);
}
}
}
}
mysql_free_result(res_ptr);
}
if(lEvent<10000000)
lEvent++;
if((lEvent>lRunTime)&&(lRunTime!=-1))
break;
//延时
sleep(iIntervalTime);
}
mysql_close(&my_cn);
return(0);
}
/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
文件名称:gsmd.c
功能说明:短信发送程序入口
编者信息:lyserver
联系方式:http://blog.csdn.net/lyserver
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
#include "daemon.h"
#include "sms.h"
#include "inifile.h"
#include "stringex.h"
#include "/usr/include/mysql/mysql.h"
/*全局变量*/
struct SMS_INFO *hModem; //短信猫设备变量
char szServer[32]; //数据库服务器名称
char szDatabase[24]; //数据库名称
char szUserName[12]; //数据库用户名
char szPassword[12]; //数据库密码
long lRunTime; //事件发生次数
int iIntervalTime; //事件间隔时间
int MessageLoop(FILE *hLog); //函数声明,主程序代码片段
int main(int argc,char *argv[]) //程序入口
{
FILE *hLog;
int iCommPort=1,iBaudRate=19200; //串口设置变量,iCommPort:串口号,iBaudRate:波特率,iDelayTime:延时
int iDelayTime=4;
char szAreaCode[5],szSmsCode[16],chSmsType; //短信号码设置变量,szAreaCode:小灵通区号,szSmsCode:短信中心号码,chSmsType:短信中心号码类型
struct FILE_INFO *hFile; //配置文件变量
//读取参数配置文件
hFile=OpenIniFile("gsmd.conf");
if(hFile==NULL)return(1);
strcpy(szSmsCode,GetKeyValue(hFile,"MOBILE_CODE","SMS_CODE"));
chSmsType=GetKeyValue(hFile,"MOBILE_CODE","SMS_CODE")[0];
strcpy(szAreaCode,GetKeyValue(hFile,"MOBILE_CODE","AREA_CODE"));
iCommPort=atol(GetKeyValue(hFile,"COMM_SETTING","COMM_PORT"));
iBaudRate=atol(GetKeyValue(hFile,"COMM_SETTING","BAUD_RATE"));
strcpy(szServer,GetKeyValue(hFile,"DATABASE","SERVER"));
strcpy(szDatabase,GetKeyValue(hFile,"DATABASE","DATABASE"));
strcpy(szUserName,GetKeyValue(hFile,"DATABASE","USERNAME"));
strcpy(szPassword,GetKeyValue(hFile,"DATABASE","PASSWORD"));
lRunTime=atol(GetKeyValue(hFile,"EVENT","RUN_TIME"));
iDelayTime=atol(GetKeyValue(hFile,"EVENT","DELAY_TIME"));
iIntervalTime=atol(GetKeyValue(hFile,"EVENT","INTERVAL_TIME"));
//关闭配置文件
CloseIniFile(hFile);
//打开短信猫设备
hModem=OpenModem(iCommPort,iBaudRate,1000);
if(hModem==NULL)return(2);
printf("SMS短信服务程序已成功启动......\n");
//对短信猫设备变量进行一些设置
strncpy(hModem->AREA_CODE,szAreaCode,4); //设置区号
hModem->AREA_CODE[4]='\0';
strcpy(hModem->SMS_CODE,szSmsCode);
hModem->SMS_CODE_TYPE=chSmsType;
hModem->iDelayTime=iDelayTime;
TEL2PDU(hModem->SMS_CODE,hModem->SMS_CODE_PDU,hModem->AREA_CODE); //对短信中心号码进行PDU编码
//将程序转为后台运行
//MakeDaemon("gsmd.log",&MessageLoop);
MessageLoop(NULL);
//关闭短信猫
CloseModem(hModem);
printf("SMS短信服务程序已停止运行!\n");
return(0);
}
int MessageLoop(FILE *hLog) //函数声明,主程序代码片段
{
long lEvent=0;
int col_num,row_num;
MYSQL my_cn;
MYSQL_RES *res_ptr;
MYSQL_ROW my_row;
char szSQL[256];
//打开数据库
mysql_init(&my_cn);
if(mysql_real_connect(&my_cn,szServer,szUserName,szPassword,szDatabase,0,NULL,CLIENT_FOUND_ROWS)==NULL)
return(-1);
//循环查询是否有等待发送的短信
while(1)
{
strcpy(szSQL,"select DEST_TERMINAL_ID,MSG_CONTENT,ROW_ID from submit_msg_base ");
strcat(szSQL,"where instr('130131132133134155156135',left(DEST_TERMINAL_ID,3))>0 ");
strcat(szSQL,"and (ROW_ID Not In (select ROW_ID from submit_msg_status_sending))");
if(mysql_query(&my_cn,szSQL)) //如果有查询结果
{
res_ptr=mysql_store_result(&my_cn);
if(res_ptr)
{
row_num=mysql_num_rows(res_ptr);
col_num=mysql_num_fields(res_ptr);
if(row_num>0)
{
while((my_row=mysql_fetch_row(res_ptr)))
{
//将未发短信放入正在发送的表中
sprintf(szSQL,"insert into submit_msg_status_sending(ROW_ID) values(%s)",my_row[2]);
mysql_query(&my_cn,szSQL);
//发送短信
if((SendMessage(hModem,my_row[0],my_row[1]))==1) //发送成功
{
//写日志
if(hLog!=NULL){
sprintf(szSQL,"ROW_ID为%d的短信于%d成功发送。\n",my_row[2],GetCurrentDateAndTime());
fputs(szSQL,hLog);
fflush(hLog);}
//将已发短信放入已发送的表中
sprintf(szSQL,"insert into submit_msg_status_sended(ROW_ID) values(%s)",my_row[2]);
mysql_query(&my_cn,szSQL);
}
}
}
}
mysql_free_result(res_ptr);
}
if(lEvent<10000000)
lEvent++;
if((lEvent>lRunTime)&&(lRunTime!=-1))
break;
//延时
sleep(iIntervalTime);
}
mysql_close(&my_cn);
return(0);
}
七、本程序在red linux下使用cc编译器进行编译,make.txt文件如下:
cc gsmd.c -o gsmd -I /usr/include/mysql -L /usr/lib/mysql -l mysqlclient -lz
至此,一个完整的短信收发程序已成功创建完毕。