有人做过在linuxlinux lamp环境搭建下给手机发短信的程序吗

:转载时请以超链接形式标明文章原始出处和作者信息及
今天下午在找监控资料的时候发现很多用短信报警之类的手法。发现中国移动提供了一个接口
飞信免费发短信API接口调用方式(通过HTTP访问以下网址、支持GET和POST):
=您的移动飞信登录手机号&password=您的移动飞信登录密码&sendto=接收短信的飞信好友手机号(也可以是你自己的手机号)&message=短信内容
注:需要互为移动飞信好友.短信内容最大长度为180个汉字,超过180个汉字不发送。返回的信息为UTF-8编码的中文文本信息。
&在linux下可以使用curl post这一操作 curl
&http://sms.api.bz/fetion.php?username=&password=123456&
sendto=&message=短信内容&
本文已收录于以下专栏:
相关文章推荐
以下例子发送“你好”到
发送数据是:你好
Unicode译码为:4F60597D 
AT+CMGS=019 //15(PDU 规约头固定长度15 字节)+4(报文长度4...
最近做了一些与短信相关的工作,在这里做一个学习的梳理,愿与您共同分享学习。要完成一个短信接口需要完成这样几件事儿:模板管理、接口管理、拼接接口数据
模板管理:最基本的对短信进行增删该查;第二,将...
去年在博客里发这个贴时,只将主程序代码贴了出来,导致信息不完整,让读者根本无法进行实验。为此,现将全部代码贴出来,为想在linux下开发基于短信猫的短信收发程序的朋友提供一点参考。    首先,我根据...
近来由于项目需要,需要用到手机短信验证码的功能,其中最主要的是用到了第三方提供的短信平台接口WebService客户端接口,下面我把我在项目中用到的记录一下,以便给大家提供个思路,由于本人的文采有限,...
短信验证码在各类App和网站中广泛使用,这里介绍一些技术对接中常用的接口以及相关实例为各位提供参考。
首先,预先提供短信模板,保证通道提供稳定服务,平台进行内容审核,而后方能使用通用发送接口发短...
我们公司最近做了二个网站,都用到了短信接口了,为了找一家好的短信接口,我们找了好多家,也测试了很多家,在这里给大家分享一下,56短信网的短信接口,网址是:,也给...
1. SMS短信通
SMS短信通是中国网建提供的一个发送短信的应用,一般用于企业级用户。本博文介绍如何编写最简单的Hello World级Java程序,实现向指定手机号发送短信的功能。由于SMS短信...
他的最新文章
讲师:汪剑
讲师:刘道宽
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)5666人阅读
C/C++(6)
&&& 去年在博客里发这个贴时,只将主程序代码贴了出来,导致信息不完整,让读者根本无法进行实验。为此,现将全部代码贴出来,为想在linux下开发基于短信猫的短信收发程序的朋友提供一点参考。
&&& 首先,我根据功能需要创建了几个头文件,一个是stringex.h,包含一些字符串辅助函数;一个是inifile.h,包含读写类似windows环境下ini文件的函数;一个是daemon.h,包含创建linux守护进程(类似windows后台程序)的函数,还有一个是sms.h,包含串口通信相关函数,具体代码如下:
&&& 一、stringex.h,自定义字符串辅助函数库:
/* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
文件名称:stringex.c
功能说明:字符串增强函数库
编者信息:lyserver
联系方式:http://blog.csdn.net/lyserver
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& */
#include &stdio.h&
#include &string.h&
#include &iconv.h&
#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) //截去左边的空格
while(*p!='/0')
if(32!=(BYTE)*p)
l=strlen(inbuff)-(p-inbuff);
strncpy(outbuff,p,l);;
outbuff[l]='/0';
void rtrim(BYTE *outbuff,BYTE *inbuff) //截去右边的空格
p+=(strlen(inbuff)-1);
while(p&inbuff)
if(32!=(BYTE)*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)-
strncpy(outbuff,inbuff+start,length);
outbuff[length]='/0';
int instr(int start,BYTE *inbuff,BYTE *strfind) //查找strfind在字符串inbuff中出现的位置
if(strlen(strfind)==1)
p=strchr(inbuff+start,strfind[0]);
if(p!=NULL)
return -1;
p=strstr(inbuff+start,strfind);
if(p!=NULL)
return -1;
void replace(BYTE *outbuff,BYTE *inbuff,BYTE *strfind,BYTE *strreplace) //用strreplace替换字符串中出现的strfind
BYTE buff[STRING_EX_BUFFER_SIZE];
sprintf(buff,&%s%s&,inbuff,strreplace);
p=strtok(buff,strfind);
outbuff[0]='/0';
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)
unsigned long lASCII;
BYTE szbuff[STRING_EX_BUFFER_SIZE];
memset(szbuff,0,STRING_EX_BUFFER_SIZE);
for(i=0;i&strlen(inbuff);i++)
if(inbuff[i] & 0x80) //on BYTE of UTF8
lASCII = inbuff[i];
if(lASCII & 0xf)
sprintf(szbuff,&%s00%2X&,szbuff,lASCII);
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);
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);
else//if((0x80 &=inbuff[i]) & (inbuff[i] & 0xc0)) //not the first byte of UTF8 BYTEacter
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';
szbuff[0]='/0';
for(i=0;i&iLi+=4)
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) //字符集转换(实现各种编码)
size_t inleft=strlen(inbuff)+1;
size_t outleft=STRING_EX_BUFFER_SIZE;
char buff[STRING_EX_BUFFER_SIZE],*
//打开需要转换的字符集
it=iconv_open(to_Charset,from_Charset);
if((int)it==-1)
return -1;
//进行转换
memset(buff,0,STRING_EX_BUFFER_SIZE);
if((int)iconv(it,(char**)&inbuff,&inleft,(char**)&pbuff,&outleft)==-1)
return -2;
strcpy(outbuff,buff);
//转换结束
iconv_close(it);
return STRING_EX_BUFFER_SIZE-
&&& 二、inifile.h,配置文件读写函数库:
/* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
文件名称:inifile.h
功能说明:配置文件读写函数库
编者信息:lyserver
联系方式:http://blog.csdn.net/lyserver
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& */
#ifndef INI_FILE_DEF
#define INI_FILE_DEF
#include &stdio.h&
#include &string.h&
#include &sys/stat.h&
#include &stringex.h&
struct KEY_INFO
BYTE Name[64]; //Key名称
BYTE Value[64]; //Key值
LPBYTE pC //指向Key注释的指针
struct NODE_INFO
BYTE Name[64]; //节名称
LPBYTE pC //节注释
int iK //键计数
struct KEY_INFO *pK //键数组指针
struct FILE_INFO
FILE *hF //文件句柄
int iN //文件包含的节数
struct NODE_INFO *pN //节数组指针
struct NODE_INFO *pN //当前节指针
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_F //局部静态结构变量
int iFileSize=0,iLineT //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;
if(szLineBuff[0]=='[')
iLineType=(instr(1,szLineBuff,&]&)&0)?1:3;
if(instr(1,szLineBuff,&=&)&0)
iLineType=2;
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.pN
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);
case 1: //节行
m_File.iNodes++; //节计数加1
if(m_File.pNode==NULL)
m_File.pNodes=malloc(NODE_SIZE); //申请一个新的节
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);
m_File.pNode-&pComment=malloc(2);
m_File.pNode-&pComment[0]='/0';
case 2: //键值对行
m_File.pNode-&iKeys++;
if(m_File.pNode-&pKeys==NULL)
m_File.pNode-&pKeys=malloc(KEY_SIZE); //申请一个新的键值对
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);
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);
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);
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)
if(strcmp(pFile-&pNode-&Name,pNodeName)==0) //如果指定的节名称与当前节名称相同
for(i=0;i&pFile-&pNode-&iKi++)
if(strcmp(pFile-&pNode-&pKeys[i].Name,pKeyName)==0)
return(pFile-&pNode-&pKeys[i].Value);
pFile-&pNode=pFile-&pN
for(i=0;i&pFile-&iNi++)
if(strcmp(pFile-&pNode-&Name,pNodeName)==0)
for(j=0;j&pFile-&pNode-&iKj++)
if(strcmp(pFile-&pNode-&pKeys[j].Name,pKeyName)==0)
return(pFile-&pNode-&pKeys[j].Value);
pFile-&pNode++;
return(NULL);
int CloseIniFile(struct FILE_INFO *pFile) //关闭配置文件
if(pFile-&pNodes!=NULL)
pFile-&pNode=pFile-&pN
for(i=0;i&pFile-&iNi++)
free(pFile-&pNode-&pComment); //释放节注释
for(j=0;j&pFile-&pNode-&iKj++)
free(pFile-&pNode-&pKeys[j].pComment); //释放键值对注释
free(pFile-&pNode-&pKeys); //释放键值对
pFile-&pNode++;
free(pFile-&pNodes);
fclose(pFile-&hFile);
&&& 三、daemon.h,守护进程函数库:
/* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
文件名称:daemon.h
功能说明:实现守护进程
编者信息:lyserver
联系方式:http://blog.csdn.net/lyserver
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& */
#ifndef DAEMON_PROCESS_DEF
#define DAEMON_PROCESS_DEF
#include &stdio.h&
#include &stdlib.h&
#include &signal.h&
#include &fcntl.h&
#include &errno.h&
#include &time.h&
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)
//创建一个新的会议组
if(setsid()&0)
//退出子进程,让孙进程失去终端控制
if(fork()!=0)
//忽略SIGCHLD信号
signal(SIGCHLD,SIG_IGN);
//处理日志文件
if(pLogFileName!=NULL)
if((fpLog=fopen(pLogFileName,&r&))==NULL) //如果文件不存在
fpLog=fopen(pLogFileName,&w&);
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()
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);
&&& 四、asynccom.h,串口通信函数库:
/* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
文件名称:asynccom.h
功能说明:串口异步通信函数库
编者信息:lyserver
联系方式:http://blog.csdn.net/lyserver
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& */
#ifndef ASYNC_COM_DEF
#define ASYNC_COM_DEF
#include &stdio.h&
#include &fcntl.h&
#include &termios.h&
#include &sys/ioctl.h&
#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串口端口号,返回句柄
char szCommFileName[127];
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 speed_value[]={B400,B1,B4800};
int speed_name[]={00,,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&sizeof(speed_name)/sizeof(int);i++)
if(BaudRate==speed_name[i])
options.c_cflag|=speed_value[i];
//设置校验位
switch(ParityBits)
case 'o':case 'O': //奇校验
options.c_cflag|=(PARODD|PARENB);
options.c_iflag|=INPCK;
case 'e':case 'E': //偶校验
options.c_cflag|=PARENB;
options.c_cflag&=~PARODD;
options.c_iflag|=INPCK;
case 's':case 'S': //Space校验
options.c_cflag&=~PARENB;
options.c_cflag&=~CSTOPB;
options.c_iflag|=INPCK;
default: //默认为无校验,即'n'或'N'
options.c_cflag&=~PARENB;
options.c_iflag&=~INPCK;
//设置数据位
if(DataBits==7)
options.c_cflag|=CS7;
options.c_cflag|=CS8;
//设置停止位
if(StopBits==1)
options.c_cflag&=~CSTOPB;
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) //以同步方式读串口
static unsigned char szBuff[256]; //数据缓存
memset(szBuff,0,256);
iBytes=read(hComm,szBuff,256);
return(szBuff);
&&& 五、sms.h,基于短信猫的短信收发函数库:
/* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
文件名称: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 hC //短信设备句柄
int iDelayT //等待延时
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:重试次数
static struct SMS_INFO m_S
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&iRi++)
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 iPacketL //数据包长度,从第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:iTextL
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) //辅助函数,向短信猫写数据
for(i=0;i&iRi++)
WriteComm(hComm,pMessage);
res=ReadModem(hComm,10);
if(res==1)
return(1);
return(0);
int ReadModem(int hComm,int iRetry) //辅助函数,度短信猫的反馈信息,-1:错误,0:超时,1:正确
for(i=0;i&iRi++)
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字符串
BYTE szBuff[16];//临时变量
//根据是否有区号判断号码是否为小灵通
if(pSrcCode[0]=='0') //如果是,则加上106前缀
sprintf(szBuff,&106%s&,pSrcCode);
//根据长度是否小于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);
strcpy(szBuff,pSrcCode);
//判断加上前缀后的号码长度是否为奇数,如果是,则在最后补&F&字符
l=strlen(szBuff)+1;
if((l % 2)==0)
sprintf(szBuff,&%sF&,szBuff);
//对号码进行PDU编码,即奇偶对调
for(i=0;i&l;i+=2)
pDstCode[i]=szBuff[i+1];
pDstCode[i+1]=szBuff[i];
pDstCode[l]='/0';
void PDU2TEL(LPBYTE pSrcCode,LPBYTE pDstCode) //辅助函数,PDU字符串转电话号码
BYTE szBuff[16]; //临时变量
memset(szBuff,0,16);
//奇偶对调
for(i=0;i&strlen(pSrcCode);i+=2)
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);
&&&& 六、gsmd.c,短信收发主程序:
/* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
文件名称: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 *hM //短信猫设备变量
char szServer[32]; //数据库服务器名称
char szDatabase[24]; //数据库名称
char szUserName[12]; //数据库用户名
char szPassword[12]; //数据库密码
long lRunT //事件发生次数
int iIntervalT //事件间隔时间
int MessageLoop(FILE *hLog); //函数声明,主程序代码片段
int main(int argc,char *argv[]) //程序入口
int iCommPort=1,iBaudRate=19200; //串口设置变量,iCommPort:串口号,iBaudRate:波特率,iDelayTime:延时
int iDelayTime=4;
char szAreaCode[5],szSmsCode[16],chSmsT //短信号码设置变量,szAreaCode:小灵通区号,szSmsCode:短信中心号码,chSmsType:短信中心号码类型
struct FILE_INFO *hF //配置文件变量
//读取参数配置文件
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=chSmsT
hModem-&iDelayTime=iDelayT
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_
MYSQL_RES *res_
MYSQL_ROW my_
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);
//循环查询是否有等待发送的短信
strcpy(szSQL,&select DEST_TERMINAL_ID,MSG_CONTENT,ROW_ID from submit_msg_base &);
strcat(szSQL,&where instr('',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&)
if((lEvent&lRunTime)&&(lRunTime!=-1))
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
&&& 至此,一个完整的短信收发程序已成功创建完毕。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:288276次
积分:4055
积分:4055
排名:第8124名
原创:91篇
转载:10篇
评论:301条
(1)(3)(1)(1)(1)(1)(1)(2)(2)(1)(2)(3)(3)(1)(1)(1)(2)(4)(1)(2)(1)(10)(4)(19)(11)(3)(11)(6)(2)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'

我要回帖

更多关于 linux sim900发短信 的文章

 

随机推荐