//傳輸文件的服務(wù)器端
//這個(gè)程序在服務(wù)器端要一直開著,否則客戶端連接不了服務(wù)器
//客戶--->左右軟件--->巨瀾短信網(wǎng)關(guān)
unit uServer;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, IdBaseComponent, IdComponent, IdTCPServer,
ComCtrls,uImpTxt, DB,ADODB,IniFiles;
type
//********************************************************************
//自定義類型
THandle = Integer;
JL_HANDLE = Integer;
PJL_HANDLE = ^JL_HANDLE;
//以HTTP方式登陸返回操作句柄,當(dāng)調(diào)用退出登陸時(shí),此句柄自動(dòng)失效。// 參數(shù)說(shuō)明
T_JL_TCPLogin = function(strHost: Pchar; // strHost: 主機(jī)名稱或者IP地址: ‘http://www./ 不用改變
nPort: Integer; // nPort: 端口號(hào) : 6688 不用改變
strUserId: Pchar; // strUserId: 用戶名
strPassword: Pchar; // strPassword: 用戶密碼
nType: Integer; // nType連接類型,為 1 表示只發(fā)送, 為 2表示即可發(fā)送也可接收 默認(rèn)為 2
pRtnHandle: PJL_HANDLE): Integer stdcall; // pRtnHandle: 返回操作句柄
//退出登陸,此句柄自動(dòng)失效
T_JL_Logout = function(pHandle: JL_HANDLE): Integer stdcall; // pRtnHandle: 登陸時(shí)的操作句柄
//群發(fā)短信息
T_JL_SendMsg = function(pHandle: JL_HANDLE; //操作句柄
strFromPhone: Pchar; // strFromPhone 短消息發(fā)送者手機(jī)號(hào)碼
strToPhone: Pchar; // strToPhone 目的手機(jī)號(hào)碼,如果有多個(gè)號(hào)碼,用逗號(hào)進(jìn)行分割,如13900000000, 13911111111, ...
strContent: Pchar; // strContent 信息內(nèi)容,信息長(zhǎng)度不超過(guò)140字節(jié),否則將返回 JL_ERR_CONTENT
strSendTime: Pchar): Integer stdcall; // strSendTime 定時(shí)發(fā)送時(shí)間。格式:yyyy-mm-dd hh:mm:ss 為空時(shí),表示立即發(fā)送
//單發(fā)短信息
T_JL_SingleSendMsg = function(pHandle: JL_HANDLE; //操作句柄
strSerNo: PChar; //自定義編號(hào)-以對(duì)應(yīng)相應(yīng)的狀態(tài)報(bào)告
strFromPhone: Pchar; // strFromPhone 短消息發(fā)送者手機(jī)號(hào)碼
strToPhone: Pchar; // strToPhone 目的手機(jī)號(hào)碼,如果有多個(gè)號(hào)碼,用逗號(hào)進(jìn)行分割,如13900000000, 13911111111, ...
strContent: Pchar; // strContent 信息內(nèi)容,信息長(zhǎng)度不超過(guò)140字節(jié),否則將返回 JL_ERR_CONTENT
strSendTime: Pchar): Integer stdcall; // strSendTime 定時(shí)發(fā)送時(shí)間。格式:yyyy-mm-dd hh:mm:ss 為空時(shí),表示立即發(fā)送
//查詢帳戶余額 -參數(shù):fBalance:返回金額,單位為元
T_JL_GetAccountBalance = function(pHandle: JL_HANDLE; fBalance: PSingle): Integer stdcall;
// 查詢單價(jià) -參數(shù):fPrice:返回金額,單位為元
T_JL_GetAccountPrice = function(Handle: JL_HANDLE; fPrice: PSingle): Integer stdcall;
// 修改用戶密碼
T_JL_ModifyPassword = function(pHandle: JL_HANDLE; // 操作句柄
strNewPassword: Pchar): Integer stdcall; //strNewPassword:新的密碼
// 接收短信返回的狀態(tài)報(bào)告 pstrPhone [21] pstrDescribe[255]
T_JL_GetOneReport = function(pHandle: JL_HANDLE; // 操作句柄
pstrSerNo: PChar; //用戶自定義序列(單發(fā)時(shí)用戶傳過(guò)去的參數(shù))
pnReqID: PInteger; //返回MO短信ID
pstrPhone: Pchar; //字符串緩沖區(qū),大小至少為21字節(jié),返回接收手機(jī)號(hào)碼
pnStatus: PInteger; // 返回短信息接收狀態(tài) 0:發(fā)送失敗 1:信息已發(fā)送到網(wǎng)關(guān) 3:信息已發(fā)送到手機(jī)
pstrDescribe: Pchar): Integer stdcall; //字符串緩沖區(qū),大小至少為256字節(jié),返回狀態(tài)描述
T_JL_GetOneSM = function(pHandle: JL_HANDLE; // 操作句柄
pnMsgID: PInteger; //信息id
strFrom: Pchar; //返回發(fā)送者的手機(jī)號(hào)碼 字符串緩沖區(qū),大小至少為21字節(jié)
strCreateTime: Pchar; // 返回發(fā)送時(shí)間 字符串緩沖區(qū),大小至少為20字節(jié)
strContent: Pchar): Integer stdcall; //返回消息內(nèi)容 字符串緩沖區(qū),大小至少為256字節(jié)。
T_JL_GetOneSM_Ex = function(pHandle: JL_HANDLE; // 操作句柄
pnMsgID: PInteger; //信息id
strFrom: Pchar; //返回發(fā)送者的手機(jī)號(hào)碼 字符串緩沖區(qū),大小至少為21字節(jié)
strTo: Pchar; //字符串緩沖區(qū),大小至少為21字節(jié),返回來(lái)源端口號(hào)
strCreateTime: Pchar; // 返回發(fā)送時(shí)間 字符串緩沖區(qū),大小至少為20字節(jié)
strContent: Pchar): Integer stdcall; //返回消息內(nèi)容 字符串緩沖區(qū),大小至少為256字節(jié)。
//********************************************************************
type
TFormServer = class(TForm)
IdTCPServer1: TIdTCPServer;
BtnStart: TButton;
StatusBar1: TStatusBar;
BtnStop: TButton;
LabeledEdit1: TLabeledEdit;
ListBox1: TListBox;
ADOQuery1: TADOQuery;
ADOQuery2: TADOQuery;
ADOConnection1: TADOConnection;
ADOQuery3: TADOQuery;
ADOQuery4: TADOQuery;
procedure IdTCPServer1Execute(AThread: TIdPeerThread);
procedure BtnStartClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure BtnStopClick(Sender: TObject);
procedure IdTCPServer1Connect(AThread: TIdPeerThread);
procedure ShowResultMsg(num: Integer);
private
{ Private declarations }
public
{ Public declarations }
OneHandle: THandle; //定義一個(gè)句柄變量
pRtnHandle: JL_HANDLE; //定義一個(gè)句柄變量
JL_TCPLogin: T_JL_TCPLogin; //登陸
JL_Logout: T_JL_Logout; //退出
JL_GetAccountPrice: T_JL_GetAccountPrice; //單價(jià)/條
JL_GetAccountBalance: T_JL_GetAccountBalance; //帳戶余額
JL_ModifyPassword: T_JL_ModifyPassword; //修改密碼
JL_GetOneSM: T_JL_GetOneSM; //收取回復(fù)信息(HTTP)
JL_GetOneSM_Ex: T_JL_GetOneSM_Ex; //收取回復(fù)信息(TCP)
JL_GetOneReport: T_JL_GetOneReport; //收取狀態(tài)報(bào)告
JL_SingleSendMsg: T_JL_SingleSendMsg; //單發(fā)信息
JL_SendMsg: T_JL_SendMsg; // 群發(fā)信息
end;
var
FormServer: TFormServer;
const
FFileName=‘d:\sms.txt‘; //參數(shù)有待放進(jìn)INI文件中
FPort=9925;
FUserName=‘‘; //登錄巨瀾短信網(wǎng)關(guān)用戶名和密碼
FPWS=‘‘;
implementation
uses uCommFunc;
{$R *.dfm}
//------返回錯(cuò)誤列表--------------------------------------------------
procedure tformserver.ShowResultMsg(num: Integer);
begin
case num of
0: MessageBox(Handle, ‘正常!‘, ‘Surge‘, MB_ICONASTERISK);
-1: MessageBox(Handle, ‘EPID錯(cuò)誤‘, ‘Surge‘, MB_ICONHAND);
-2: MessageBox(Handle, ‘無(wú)該用戶‘, ‘Surge‘, MB_ICONHAND);
-3: MessageBox(Handle, ‘注冊(cè)碼錯(cuò)‘, ‘Surge‘, MB_ICONHAND);
-4: MessageBox(Handle, ‘用戶被停用‘, ‘Surge‘, MB_ICONHAND);
-5: MessageBox(Handle, ‘未注冊(cè)成功‘, ‘Surge‘, MB_ICONHAND);
-6: MessageBox(Handle, ‘超出使用日期‘, ‘Surge‘, MB_ICONHAND);
-7: MessageBox(Handle, ‘費(fèi)用不足‘, ‘Surge‘, MB_ICONHAND);
-8: MessageBox(Handle, ‘源手機(jī)錯(cuò)誤‘, ‘Surge‘, MB_ICONHAND);
-9: MessageBox(Handle, ‘目的手機(jī)錯(cuò)誤‘, ‘Surge‘, MB_ICONHAND);
-10: MessageBox(Handle, ‘信息內(nèi)容錯(cuò)誤‘, ‘Surge‘, MB_ICONHAND);
-11: MessageBox(Handle, ‘連接失敗‘, ‘Surge‘, MB_ICONHAND);
-12: MessageBox(Handle, ‘系統(tǒng)內(nèi)部錯(cuò)誤或者無(wú)效的客戶狀態(tài)‘, ‘Surge‘, MB_ICONHAND);
-13: MessageBox(Handle, ‘客戶權(quán)限不對(duì)‘, ‘Surge‘, MB_ICONHAND);
-14: MessageBox(Handle, ‘不是從指定的IP處登錄‘, ‘Surge‘, MB_ICONHAND);
-15: MessageBox(Handle, ‘賬號(hào)已經(jīng)登錄(TCP)‘, ‘Surge‘, MB_ICONHAND);
-16: MessageBox(Handle, ‘內(nèi)部通訊錯(cuò)誤‘, ‘Surge‘, MB_ICONHAND);
-17: MessageBox(Handle, ‘無(wú)可用的MT通道‘, ‘Surge‘, MB_ICONHAND);
-18: MessageBox(Handle, ‘不支持該功能‘, ‘Surge‘, MB_ICONHAND);
-19: MessageBox(Handle, ‘未定義錯(cuò)誤‘, ‘Surge‘, MB_ICONHAND); //-------------未定義錯(cuò)誤
-20: MessageBox(Handle, ‘未知錯(cuò)誤‘, ‘Surge‘, MB_ICONHAND);
-21: MessageBox(Handle, ‘請(qǐng)求過(guò)于頻繁‘, ‘Surge‘, MB_ICONHAND);
-22: MessageBox(Handle, ‘信息內(nèi)容有非法關(guān)鍵字‘, ‘Surge‘, MB_ICONHAND);
-23: MessageBox(Handle, ‘錯(cuò)誤的產(chǎn)品ID‘, ‘Surge‘, MB_ICONHAND);
-24: MessageBox(Handle, ‘發(fā)送失?。瑼gent 斷線‘, ‘Surge‘, MB_ICONHAND);
-25: MessageBox(Handle, ‘發(fā)送失?。璖MSC 斷線‘, ‘Surge‘, MB_ICONHAND);
-26: MessageBox(Handle, ‘發(fā)送失?。瑼gent 與 SMSC 之間斷線‘, ‘Surge‘, MB_ICONHAND);
-27: MessageBox(Handle, ‘錯(cuò)誤的指令或格式‘, ‘Surge‘, MB_ICONHAND);
else
MessageBox(Handle, ‘未知錯(cuò)誤‘, ‘Surge‘, MB_ICONHAND);
end;
end;
procedure TFormServer.IdTCPServer1Execute(AThread: TIdPeerThread);
//const
// c_sql=‘select * from sms_msg_server ‘+ //status:0/1/2 待發(fā)/成功/失敗
// ‘ where status=0 or status=2 ‘; //待發(fā)和曾經(jīng)發(fā)送失敗的都要發(fā)
var
AFileStream: TFileStream;
cmd:string;
DllPaht: string; // DLL的地址
rtn: Integer; //巨瀾的函數(shù)是否執(zhí)行成功
mtel:string; //手機(jī)號(hào)碼
content:string; //短信內(nèi)容
SendTimes:Integer;//發(fā)送次數(shù)
i:Integer; //單條發(fā)送次數(shù)
iSuccess:Integer; //發(fā)送成功條數(shù)
price:Double; //短信單價(jià)
money:Double; //發(fā)送短信金額
INIFile:TIniFile;
MyCs:TRTLCriticalSection;//臨界區(qū)
procedure UpdateStatusDate; //更新狀態(tài)時(shí)間(不論成功或者失敗)
begin
with ADOQuery3 do
begin
Close;
sql.Clear;
SQL.Text:=‘update sms_msg_server set status_date=:statusdate ‘+
‘ mtel:=:mtel and ‘+
‘ create_date=:createdate ‘; //create_date是唯一的
Parameters.ParamByName(‘status_date‘).Value:=Now;
Parameters.ParamByName(‘mtel‘).Value:=ADOQuery2.fieldbyname(‘mtel‘).AsString;
Parameters.ParamByName(‘create_date‘).Value:=ADOQuery2.fieldbyname(‘create_date‘).AsDateTime;
ExecSQL;
end;
end;
begin
InitializeCriticalSection(MyCs);//初始化臨界區(qū)
with AThread.Connection do
begin
cmd := UpperCase(ReadLn);
if cmd=‘BEGIN‘ then
begin
EnterCriticalSection(MyCs); //進(jìn)入臨界區(qū),從流生成文本文件,以及將該文本文件寫進(jìn)數(shù)據(jù)表這一段要使用臨界區(qū)保護(hù)
try
AFileStream := TFileStream.Create(FFileName, fmCreate);//建立文件流準(zhǔn)備接收
try
ReadStream(AFileStream, -1, true); //讀入全部直到結(jié)束connect
Application.ProcessMessages;
finally
AFileStream.Free; //釋放文件流
end;
if not TxtToDataset(ADOQuery1,FFileName,‘,‘) then //將文本文件寫入數(shù)據(jù)庫(kù)
Application.MessageBox(‘文本寫入數(shù)據(jù)庫(kù)失敗‘, ‘錯(cuò)誤‘, MB_OK +
MB_ICONSTOP);
finally
LeaveCriticalSection(MyCs); //離開臨界區(qū)
end;
//將短信發(fā)送給巨瀾短信網(wǎng)關(guān)
//登錄巨瀾
if (OneHandle=0) or (pRtnHandle=0) then begin //未登錄
DllPaht := ExtractFilePath(Application.ExeName) + ‘\JL_ISP.dll‘; //獲得DLL的地址
OneHandle := LoadLibrary(Pchar(DllPaht)); //動(dòng)態(tài)載入DLL,并返回其句柄
try
if OneHandle <> 0 then //如果載入DLL成功則獲取DLL函數(shù)的地址
begin
@JL_TCPLogin := GetProcAddress(OneHandle, ‘JL_TCPLogin‘);
@JL_Logout := GetProcAddress(OneHandle, ‘JL_Logout‘);
@JL_GetAccountPrice := GetProcAddress(OneHandle, ‘JL_GetAccountPrice‘);
@JL_GetAccountBalance := GetProcAddress(OneHandle, ‘JL_GetAccountBalance‘);
@JL_ModifyPassword := GetProcAddress(OneHandle, ‘JL_ModifyPassword‘);
@JL_GetOneReport := GetProcAddress(OneHandle, ‘JL_GetOneReport‘);
@JL_GetOneSM := GetProcAddress(OneHandle, ‘JL_GetOneSM‘);
@JL_GetOneSM_Ex := GetProcAddress(OneHandle, ‘JL_GetOneSM_Ex‘);
@JL_SingleSendMsg := GetProcAddress(OneHandle, ‘JL_SingleSendMsg‘);
@JL_SendMsg := GetProcAddress(OneHandle, ‘JL_SendMsg‘);
end;
if not (@JL_TCPLogin = nil) then //登錄巨瀾服務(wù)器
begin
rtn := JL_TCPLogin( //函數(shù)定義見(jiàn)Type部分。
‘http://www./
6688,
Pchar(fusername),
Pchar(fpws),
2,
@pRtnHandle);
ShowResultMsg(rtn);
if rtn <> 0 then
begin
pRtnHandle := 0;
OneHandle := 0;
end;
end
else
RaiseLastOSError; //報(bào)錯(cuò)
except
MessageBox(Handle, ‘系統(tǒng)嚴(yán)重錯(cuò)誤,請(qǐng)重新登陸!!‘, ‘Surge‘, MB_ICONASTERISK);
end;
end;
//單條短信循環(huán)發(fā)送
with ADOQuery2 do
begin
Close;
SQL.Clear;
SQL.Text:=‘select * from sms_msg_server ‘+ //status:0/1/2 待發(fā)/成功/失敗
‘ where status=0 or status=2 ‘; //發(fā)送待發(fā)和發(fā)送失敗的短信
Open;
end;
if ADOQuery2.IsEmpty then exit;
iSuccess:=0; //初始化發(fā)送成功短信條數(shù)變量
ADOQuery2.First;
while not ADOQuery2.Eof do
begin
//發(fā)送前要檢查客戶的剩余短信條數(shù),等于0則不允許發(fā)送,跳轉(zhuǎn)下一條記錄
with ADOQuery4 do
begin
Close;
SQL.Clear;
SQL.Text:=‘ select user_leftamounts from sms_user ‘+
‘ where user_name=:username ‘;
Parameters.ParamByName(‘user_name‘).Value:=ADOQuery2.fieldbyname(‘shop_name‘).AsString;
Open;
end;
if ADOQuery4.FieldByName(‘user_leftamounts‘).Value<=0 then //帳戶余額不足
begin
Application.MessageBox(PChar(ADOQuery2.fieldbyname(‘shop_name‘).AsString+‘的余額已不足‘),
‘警告‘, MB_OK + MB_ICONWARNING);
exit;
end;
mtel:=ADOQuery2.fieldbyname(‘mtel‘).AsString; //目標(biāo)手機(jī)號(hào)
content:=ADOQuery2.fieldbyname(‘content‘).AsString; //短信內(nèi)容
if (pRtnHandle = 0) or (OneHandle = 0) then //判斷是否登陸
begin
MessageBox(Handle, ‘你還沒(méi)有登陸!‘, ‘Surge‘, MB_ICONASTERISK);
exit;
end;
SendTimes:=ADOQuery2.fieldbyname(‘send_times‘).AsInteger; //短信發(fā)送次數(shù)
for i:=1 to sendtimes do
try
rtn := JL_SingleSendMsg(pRtnHandle, //函數(shù)定義見(jiàn)Type部分。
PChar(IntToStr(i)), //自定義編號(hào)-以對(duì)應(yīng)相應(yīng)的狀態(tài)報(bào)告,每次發(fā)送應(yīng)傳入不同的值,用以對(duì)應(yīng)收取到的狀態(tài)報(bào)告
‘‘, //擴(kuò)展端口號(hào)
PChar(Trim(mtel)), //群發(fā)時(shí)號(hào)碼用逗號(hào)分隔,TCP協(xié)議一次群發(fā)最多50個(gè)號(hào)碼。HTTP協(xié)議一次群發(fā)最多100個(gè)號(hào)碼。
PChar(Trim(content)), //內(nèi)容長(zhǎng)度為按 Unicode characters 類型計(jì)算 ,總長(zhǎng)度不可以超過(guò)70個(gè)字(包含簽名)
‘‘); //發(fā)送時(shí)間,暫不支持!
if rtn = 0 then //發(fā)送成功
begin
Inc(iSuccess); //累加發(fā)送成功條數(shù)
ADOQuery3.Connection.BeginTrans; //開始事務(wù)
//計(jì)算發(fā)送費(fèi)用
INIFile:=TIniFile.Create(GetINIFile);
try
price:=INIFile.ReadFloat(‘server‘,‘price‘,0.6); //獲取短信的單價(jià)
finally
INIFile.Free;
end;
money:=iSuccess*price; //發(fā)送條數(shù)*單價(jià)
with ADOQuery3 do //更新用戶余額,剩余條數(shù)
begin
Close;
SQL.Clear;
sql.Text:=‘update sms_user ‘+
‘ set user_leftmoney=user_leftmoney-:money, ‘+
‘ user_leftamounts=user_leftamounts-:amounts ‘+
‘ where user_name=:username ‘;
Parameters.ParamByName(‘user_leftmoney‘).Value:=money;
Parameters.ParamByName(‘user_leftamounts‘).Value:=iSuccess;
Parameters.ParamByName(‘user_name‘).Value:=ADOQuery2.fieldbyname(‘shop_name‘).AsString;
ExecSQL;
end;
with ADOQuery3 do //更新狀態(tài)為發(fā)送成功
begin
Close;
sql.Clear;
SQL.Text:=‘update sms_msg_server set status=1 ‘+
‘ where status=0 and ‘+
‘ mtel:=:mtel and ‘+
‘ create_date=:createdata ‘;
Parameters.ParamByName(‘mtel‘).Value:=ADOQuery2.fieldbyname(‘mtel‘).AsString;
Parameters.ParamByName(‘create_date‘).Value:=ADOQuery2.fieldbyname(‘create_date‘).AsDateTime;
ExecSQL;
end;
UpdateStatusDate; //更新狀態(tài)時(shí)間
try
ADOQuery3.Connection.CommitTrans; //提交事務(wù)
except
ADOQuery3.Connection.RollbackTrans; //回滾事務(wù)
end;
MessageBox(Handle, ‘成功發(fā)送!‘, ‘Surge‘, MB_ICONASTERISK);
end
else //發(fā)送失敗
begin
ADOQuery3.Connection.BeginTrans; //開始事務(wù)
with ADOQuery3 do
begin
Close;
sql.Clear;
SQL.Text:=‘update sms_msg_server set status=2 ‘+ //更新狀態(tài)為發(fā)送失敗
‘ where status=0 and ‘+
‘ mtel:=:mtel and ‘+
‘ create_date=:createdate ‘;
Parameters.ParamByName(‘mtel‘).Value:=ADOQuery2.fieldbyname(‘mtel‘).AsString;
Parameters.ParamByName(‘create_date‘).Value:=ADOQuery2.fieldbyname(‘create_date‘).AsDateTime;
ExecSQL;
end;
UpdateStatusDate; //更新狀態(tài)時(shí)間
try
ADOQuery3.Connection.CommitTrans; //提交事務(wù)
except
ADOQuery3.Connection.RollbackTrans; //回滾事務(wù)
end;
ShowResultMsg(rtn); //通過(guò)函數(shù)的返回值顯示相應(yīng)信息
end;
except
on e:exception do
MessageBox(Handle, PChar(e.Message) , ‘Surge‘, MB_ICONASTERISK);
//‘系統(tǒng)嚴(yán)重錯(cuò)誤,請(qǐng)重新登陸!!‘
end;
ADOQuery2.Next; //發(fā)送下一條短信
end;
end;
end;
DeleteCriticalSection(MyCs); //刪除臨界界
end;
procedure TFormServer.BtnStartClick(Sender: TObject); //啟動(dòng)SOCKET服務(wù)端
begin
IdTCPServer1.DefaultPort := strtoint(LabeledEdit1.Text); //端口
if not IdTCPServer1.Active then
try
IdTCPServer1.Active := True;
ListBox1.Items.Add(‘已啟動(dòng)‘);
except
ListBox1.Items.Add(‘啟動(dòng)失敗‘);
end;
end;
procedure TFormServer.FormClose(Sender: TObject; var Action: TCloseAction);
begin
IdTCPServer1.Active:=False;
end;
procedure TFormServer.BtnStopClick(Sender: TObject);
begin
IdTCPServer1.Active:=False;
ListBox1.Items.Add(‘已停止‘);
end;
procedure TFormServer.IdTCPServer1Connect(AThread: TIdPeerThread);
begin
ListBox1.Items.Add(‘來(lái)自 ‘
+ AThread.Connection.Socket.Binding.PeerIP
+ ‘ 的連接請(qǐng)求已被允許‘);
AThread.Connection.WriteLn(‘歡迎連接到左右軟件短信服務(wù)器‘);
end;
end.