我根据联通短信协议编写的短信接口程序,共享出来,请大家观摩一下,多提宝贵意见!谢谢!
有兴趣的留下联系方式交流交流!
//*********发送短信的线程
unit UnitClient;interface
uses
  Classes,ScktComp,sysutils,sockets,windows,activex,UnitSgipProtocol,winsock,DB,
  UnitConstant,adodb;
type
  TClientThread = class(TThread)
  private
    { Private declarations }
    socket:TClientwinsocket;
    procedure GenerateSequenceNo(var sn1:longword;var sn2:longword;var sn3:longword);
    function SendBind(sStream:TWinsocketStream):boolean;
    procedure SendUnBind(sStream:TWinsocketStream);
    procedure SendSubmit(sStream:TWinsocketStream;TmpQuery:TADOQuery);    
  protected
    procedure Execute; override;  public
    constructor creat(socket:TClientwinsocket);
  end;implementationuses UnitMain;
var   
  SN:longword=0;
{ TClientThread }constructor TClientThread.creat(socket: TClientwinsocket);
begin
  inherited create(true);
  self.socket:=socket;
  Resume;
end;procedure TClientThread.Execute;
var
  sStream:TWinsocketStream;
  TMpQuery:TADOQuery;
begin
  FreeOnTerminate:=true;
  activex.CoInitialize(nil);  
  sStream:=TWinSocketStream.Create(self.socket,WaitTimeOut);//连路无数据超时时间,联通的长连接参数还没有
  //***********Bind和bind_resp成功之后开始进入线程循环***************//
  if not sendbind(sStream) then
  begin
    sStream.Free;
    activex.CoUninitialize;
    exit;
  end;
  //****************线程循环操作**********************//
  TMPQuery:=TADOQuery.Create(nil);
  TmpQuery.ConnectionString:=SMSCenter;
  try
    while (not self.Terminated) and (socket.Connected) do
    begin
      sleep(20);
      if GetSubmit(TMpQuery) then//获得要发送数据
      begin
        Sendsubmit(sStream,TMpQuery) ;//发送短信
      end
      else
      begin
        SendUnBind(sStream);//没有则拆除连接
      end;
    end;
  finally
    TmpQuery.Free;
    clientrunning:=false;
    activex.CoUninitialize;
  end;
  //*********************线程终止********************//
end;procedure TClientThread.GenerateSequenceNo(var sn1, sn2, sn3: longword);
begin
  //*************产生消息顺序号,依据SGIP协议
  sn1:=htonl(Sequence1);
  sn2:=htonl(strtoint(formatdatetime('mmddhhmmss',now())));
  if sn=4294967295 then sn:=0
  else inc(sn);
  sn3:=htonl(sn);
end;
function TClientThread.SendBind(sStream: TWinsocketStream):boolean;
var
  b:_Bind;
  BR:_Bind_resp;
  brsize:integer;
begin
  //****************发送Bind包
  Result:=false;
  fillchar(b,sizeof(b),0);
  b.header.MsgLen:=htonl(sizeof(_bind));
  b.header.CmdID :=htonl(cmd_bind);
  GenerateSequenceNo(b.header.Sequence_number1,b.header.Sequence_number2,
                     b.header.Sequence_number3);
  b.body.login_type:=1;
  strpcopy(@b.body.Login_name,Username);
  strpcopy(@b.body.login_password,password);
  //Move('',b.body.Reserve, )********Bind的reserve字段,保留
  if sStream.Write(b,sizeof(b))<>sizeof(b) then
  begin
    socket.Close;
    exit;
  end;
  brsize:=0;
  repeat
    if sStream.WaitForData(WaitTimeOut) then
    begin
      fillchar(br,sizeof(br),0);
      brsize:=sStream.Read(br,sizeof(br));
    end
    else
      socket.Close;
  until brsize=sizeof(br);
  if (br.header.Sequence_number2=b.header.Sequence_number2)
     and (br.header.Sequence_number3=b.header.Sequence_number3)
     and (br.body.Result=0) then
  begin
    result:=true;
  end;end;

解决方案 »

  1.   

    //------------------------------------------------------------------------------
    procedure TClientThread.SendUnBind(sStream: TWinsocketStream);
    var
      ub:_Unbind;
      ur:_Unbind_Resp;
      ursize:integer;//发送unbind 包
    begin
      fillchar(ub,sizeof(ub),0);
      ub.header.MsgLen:=htonl(sizeof(_Unbind));
      ub.header.CmdID :=htonl(cmd_UNBIND);
      GenerateSequenceNo(ub.header.Sequence_number1,ub.header.Sequence_number2,
                         ub.header.Sequence_number3);  
      if sStream.Write(ub,sizeof(ub))<>sizeof(ub) then
      begin
        socket.Close;
        exit;
      end;
      ursize:=0;
      repeat
        if sStream.WaitForData(WaitTimeOut) then
        begin
          fillchar(ur,sizeof(ur),0);
          ursize:=sStream.Read(ur,sizeof(ur));
        end
        else
          socket.Close;
      until ursize = sizeof(ur);
      if (ur.header.Sequence_number2=ub.header.Sequence_number2)
         and (ur.header.Sequence_number3=ub.header.Sequence_number3) then
            socket.Close;  end;
    //------------------------------------------------------------------------------发送submit包
    procedure TClientThread.SendSubmit(sStream: TWinsocketStream;TmpQuery:TADOQuery);
    var
      s:_submit;
      sr:_Submit_Resp;
      submitPackage : Submit_Package;
      srsize:integer;
    begin
      FillChar(s,sizeof(s),0);
      s.header.MsgLen:=htonl(sizeof(s)); //因为协议定义的时候将这个写死为160个了, 正常应该是
                                         //将MSGCONTENT定义为动态数组,消息长度应该是SIZEOF数据结构加上
                                         // 动态数组的长度 靠,SIZEOF计算含动态内存分配的数据结构不准
      s.header.CmdID :=htonl(cmd_submit);
      GenerateSequenceNo(s.header.Sequence_number1,s.header.Sequence_number2,
                         s.header.Sequence_number3);
      //*********构建包体**********//
      with submitPackage do
      begin
        CorpId := UnitConstant.CorpID;
        SPNumber := UnitConstant.SPNum;
        UserCount := 1;
        with submitPackage,TmpQuery do
        begin
          ChargeNumber := '86'+FieldByName('ChargeNumber').AsString;
          UserNumber := FieldByName('UserNumber').AsString;
          ServiceType := FieldByName('ServiceType').AsString;
          FeeType := FieldByName('FeeType').AsInteger;;
          FeeValue := FieldByName('FeeValue').AsString;
          GivenValue := FieldByName('GivenValue').AsInteger;
          AgentFlag := FieldByName('AgentFlag').AsInteger;
          MorelatetoMTFlag := FieldByName('MorelatetoMTFlag').AsInteger;
          Priority := FieldByName('Priority').AsInteger;
          //ExpireTime :=
          //ScheduleTime :=
          ReportFlag := FieldByName('ReportFlag').AsInteger;
          TP_pid := 0;
          TP_udhi := 0;
          MessageCoding := FieldByName('MessageCoding').AsInteger;
          MessageType := 1;
          MessageContent := FieldByName('MessageContent').AsString;
          MessageLength := length(MessageContent);
          LinkID := FieldByName('LinkID').AsString;
        end;
        strpcopy(@s.body.SPNumber,spnumber);
        strpcopy(@s.body.ChargeNumber,ChargeNumber);
        s.body.UserCount:=UserCount;
        strpcopy(@s.body.UserNumber,UserNumber);
        strpcopy(@s.body.corpid,corpid);
        strpcopy(@s.body.ServiceType,ServiceType);
        s.body.FeeType := FeeType;
        strpcopy(@s.body.FeeValue,FeeValue);
        strpcopy(@s.body.givenvalue,inttostr(GivenValue));
        s.body.AgentFlag := AgentFlag;
        s.body.MorelatetoMTFlag := MorelatetoMTFlag;
        s.body.Priority := Priority;
        s.body.ReportFlag := ReportFlag;
        s.body.TP_pid := TP_pid;
        s.body.TP_udhi := TP_udhi;
        s.body.MessageCoding := MessageCoding;
        s.body.MessageType := MessageType;
        s.body.MessageLength:= htonl(MessageLength);
        strpcopy(@s.body.MessageContent,MessageContent);
        strpcopy(@s.body.LinkID,LinkID);
      end;
      //**************************************// 
      if sStream.Write(s,sizeof(s))<>sizeof(s) then
      begin
        socket.Close;
        exit;
      end;
      srsize:=0;
      repeat
        if sStream.WaitForData(WaitTimeOut) then
        begin
          fillchar(sr,sizeof(sr),0);
          srsize:=sStream.Read(sr,sizeof(sr));
        end
        else
          socket.Close;
      until srsize = sizeof(sr);
      if (sr.header.Sequence_number2=s.header.Sequence_number2)
         and (sr.header.Sequence_number3=s.header.Sequence_number3)
         and (sr.body.Result=0) then
      begin
        Log_Submit(submitPackage,0);
        postmessage(frmmain.Handle,showruninfo,0,integer(pchar('Submit ok')));
      end
      else
      begin
        Log_Submit(submitPackage,sr.body.Result);
        postmessage(frmmain.Handle,showruninfo,0,integer(pchar('Submit error')));
      end;
      //DeleteSubmit(TmpQuery);
    end;
    end.
      

  2.   

    服务器端监听线程:非阻塞式socket,下面主要是获得数据包然后根据不同命令字读取包的过程
    procedure TFrmMain.ServerSocketClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    var
      header:Sgip_header;
      cmdid:longword;
    begin
      //非阻塞式服务端,由客户端的读写操作触发服务器端的事件  FillChar(header,sizeof(header),0);
      if socket.ReceiveBuf(header,sizeof(header))=sizeof(header) then
      begin
        cmdid:= ntohl(header.CmdID);
        if cmdid=cmd_bind then   handleBind(socket,header)//处理bind 
        else if cmdid=cmd_DELIVER then handledeliver(socket,header)//处理deliver
        else if cmdid=cmd_UNBIND then handleunbind(socket,header)//处理unbind
        else if cmdid=cmd_REPORT then handleReport(socket,header)//处理状态报告
        else socket.Close;  //不正确的命令字,就关掉连接
      end;  end;procedure TFrmMain.HandleBind(socket: TCustomWinSocket; header: Sgip_header);
    var
      b:Sgip_Bind ;
      Br:_Bind_resp;
    begin
      fillchar(b,sizeof(b),0);
      if socket.ReceiveBuf(b,sizeof(b))<>sizeof(b) then
      begin
        socket.Close;
        exit;
      end;
      fillchar(br,sizeof(br),0);
      br.header.CmdID:=htonl(cmd_BIND_RESP);
      br.header.Sequence_number1:=header.Sequence_number1;
      br.header.Sequence_number2:=header.Sequence_number2;
      br.header.Sequence_number3:=header.Sequence_number3;
      br.header.MsgLen:=htonl(sizeof(br));
      //用户名密码校验
      if (strpas(@b.Login_name)=username) and (strpas(@b.login_password)=password) then
        br.body.Result:=0
      else br.body.Result:=1;
      //move('aaaa',br.body.Reserve,4); 现在bind包中的reserve字段还没使用
      if socket.SendBuf(br,sizeof(br))<>sizeof(br) then
      socket.Close;
    end;procedure TFrmMain.HandleDeliver(socket: TCustomWinSocket;
      header: Sgip_header);
    var
      Dr:_Deliver_Resp;
      MsgLen:integer;
      D:Sgip_deliver;
    begin
      fillchar(d,sizeof(d),0);
      if socket.ReceiveBuf(d.Deliver1,sizeof(d.Deliver1))<>sizeof(d.Deliver1) then
      begin
        socket.Close;
        exit;
      end;
      MsgLen:=ntohl(d.Deliver1.MessageLength);
      fillchar(d.Deliver2,sizeof(d.Deliver2),0);
      if socket.ReceiveBuf(d.Deliver2.MessageContent,MsgLen)<>MsgLen then //加上8是linkid的长度
      begin
        socket.Close;
        exit;
      end;
      if socket.ReceiveBuf(d.Deliver2.linkid,8)<>8 then
      begin
        socket.Close;
        exit;
      end;
      //将deliver写到数据库中
      SaveDelivery(d);  fillchar(dr,sizeof(dr),0);
      dr.header.MsgLen:=htonl(sizeof(dr));
      dr.header.CmdID:=htonl(cmd_DELIVER_RESP);
      dr.header.Sequence_number1:=header.Sequence_number1;
      dr.header.Sequence_number2:=header.Sequence_number2;
      dr.header.Sequence_number3:=header.Sequence_number3;
      dr.body.Result:=0;
      //dr.body.Reserve 用户
      if socket.SendBuf(dr,sizeof(dr))<>sizeof(dr) then
        socket.Close;
    end;procedure TFrmMain.HandleUnbind(socket: TCustomWinSocket;
      header: Sgip_header);
    var
      Ur:_Unbind_Resp;
    begin
      fillchar(ur,sizeof(ur),0);
      ur.header.MsgLen:=htonl(sizeof(ur));
      ur.header.CmdID:=htonl(cmd_UNBIND_RESP);
      ur.header.Sequence_number1:=header.Sequence_number1;
      ur.header.Sequence_number2:=header.Sequence_number2;
      ur.header.Sequence_number3:=header.Sequence_number3;
      if socket.SendBuf(ur,sizeof(ur))<>sizeof(ur) then  socket.Close;
    end;procedure TFrmMain.HandleReport(socket: TCustomWinSocket;
      header: Sgip_header);
    var
      r:Sgip_Report;
      rr:_Report_Resp;
    begin
      fillchar(r,sizeof(r),0);
      if socket.ReceiveBuf(r,sizeof(r))<>sizeof(r) then
      begin
        socket.Close;
        exit;
      end;
      //将report写入到数据库中
      SaveReport(r);  FillChar(rr,sizeof(rr),0);
      rr.header.MsgLen:=htonl(sizeof(rr));
      rr.header.CmdID:=htonl(cmd_REPORT_RESP);
      rr.header.Sequence_number1:=header.Sequence_number1;
      rr.header.Sequence_number2:=header.Sequence_number2;
      rr.header.Sequence_number3:=header.Sequence_number3;
      rr.body.Result := 0;
      //rr.body.Reserve :=
      if socket.SendBuf(rr,sizeof(rr))<>sizeof(rr) then
      socket.Close;
    end;
    function TFrmMain.Unicodetoascii(DeliverStr:Sgip_deliver):string;//将unicode编码文本转换为ascii文本
    var
      StrLength:integer;
      i:integer;
      strcode:string;
    begin
      strLength:=ntohl(deliverstr.Deliver1.MessageLength);
      For i := 1 to (strLength div 2) do
      begin
        strcode:='$'+inttohex(ord(deliverstr.Deliver2.MessageContent[2*i-1]),2)
                   +inttohex(ord(deliverstr.Deliver2.MessageContent[2*i]),2);
        result:=result+widechar(strtoint(strcode));
      end;
    end;
      

  3.   


      if socket.ReceiveBuf(header,sizeof(header))=sizeof(header) then
    这条件的ELSE怎么不处理呢?
      

  4.   

    应该加个else
    socket.close的
    呵呵程序已经通过中国联通测试了
    晕,也没人来顶顶
      

  5.   

    呵呵...SOCKET.CLOSE这样做不是正解..
    楼主的程序在不太高流量下会运行很好的.
    不过反正联通短信流量都有限制..比如一秒20条什么的..
    所以也不用考虑太多..
      

  6.   

    我做SP开发,专门做SGIP,CMPP。
    DelphiBird (爱你等于爱自己) ,halfdream(哈欠) 还有对短信感兴趣D同仁,咱们交个朋友,多交流交流,共同进步。
    我在天津, QQ:37727640
      

  7.   

    我顶!但UnitSgipProtocol, UnitConstant是你写的控件吗?为什么不贴上来呢?
      

  8.   

    要贴就贴全些,UnitSgipProtocol, UnitConstant这两个单元也一起贴出来好吗?
      

  9.   

    CMPP的程序我去年做的,现在基本运行1年了还没出什么问题
    呵呵那两个是我封装数据协议的单元
    大家着协议写就行了,我也贴出来TO  halfdream(哈欠):
    请问你有什么好的解决方案,我这个程序的弱点大概主要是:
    1.比如每对消息和消息的resp之间应该做异步处理的;建立队列机制;但是现在还没想到既能异步又能安全的解决方案;我想重开线程来做异步处理,又怕socket数据读取的时候发生冲突;比如新开线程去读RESP,保证队列不朝过联通规定的32个;但是会出现几个线程同时读SOCKET的情况;
    2.另外发送和接受应该有缓存排序机制的,这个目前我实现在数据库中了;
    3.还有就是长连接,因为联通不支持长连接,虽然它号称支持长连接,但是我找遍协议也没发现连路检测的消息;所以我在处理完所有submit命令还是会拆除连接的
      

  10.   

    unit UnitSgipProtocol;interface
    uses
      SysUtils;
    const                                       
      cmd_BIND:longword            =$1;            //对客户端验证
      cmd_BIND_RESP:longword     =$80000001;     //服务端返回验证请求
      cmd_UNBIND:longword         =$2;            //断开连接
      cmd_UNBIND_RESP:longword     =$80000002;     //返回断开连接状态
      cmd_SUBMIT:longword         =$3;            //向SMG提交MT短消息
      cmd_SUBMIT_RESP:longword     =$80000003;     //返回SP提交MT短消息状态
      cmd_DELIVER:longword         =$4;            //SMG向SP发送一条MO短消息
      cmd_DELIVER_RESP:longword    =$80000004;     //返回SMG状态
      cmd_REPORT:longword         =$5;            //向SP发送一条先前的submit命令的当前状态
      cmd_REPORT_RESP:longword     =$80000005;     //响应SMG状态
    type
     //***************消息头
      Sgip_header = packed record
        MsgLen:longword;
        CmdID:longword;
        Sequence_number1,
        Sequence_number2,
        Sequence_number3:longword;
      end;
    //***************Bind命令
      Sgip_Bind = packed record
        login_type:byte;
        Login_name : packed array[1..16] of char;
        login_password : packed array[1..16] of char;
        Reserve : packed array[1..8] of char;
      end;
    //*****************Bind_Resp命令
      Sgip_Bind_Resp = packed record
        Result:byte;      //Bind执行命令是否成功。0:执行成功其它:错误码
        Reserve:packed array[1..8] of char;
      end;
      Sgip_UnBind = packed record
      end;
      Sgip_UnBind_Resp = packed record
      end;
    //*****************Unbind命令
      Sgip_Submit=packed record
         SPNumber:packed array[1..21] of char;
         ChargeNumber:packed array[1..21] of char;
         UserCount:byte;
         UserNumber :packed array[1..21] of char;
         CorpId :packed array[1..5] of char;
         ServiceType:packed array[1..10] of char;
         FeeType:byte;
         FeeValue:packed array[1..6] of char;
         GivenValue:packed array[1..6] of char;
         AgentFlag:byte;
         MorelatetoMTFlag:byte;
         Priority:byte;
         ExpireTime:packed array[1..16] of char;
         ScheduleTime:packed array[1..16] of char;
         ReportFlag:byte;
         TP_pid:byte;
         TP_udhi:byte;
         MessageCoding:byte;
         MessageType:byte;
         MessageLength:longword;
         MessageContent:packed array[1..160] of char;  //Message Length
         LinkID:packed array[1..8] of char;
      end;
      
      //***********************Submit_Resp命令
       Sgip_Submit_Resp = packed record
         Result:byte;
         Reserve:packed array[1..8] of char;
       end;
      //***********************Deliver命令
       Sgip_Deliver1 = packed record
         UserNumber:packed array[1..21] of char;
         SPNumber:packed array[1..21] of char;
         TP_pid:byte;
         TP_udhi:byte;
         MessageCoding:byte;
         MessageLength:longword;
       end;
       sgip_deliver2 = packed record
         MessageContent :packed array[1..255] of char;    //Message Length
         LinkID:packed array[1..8] of char;
       end;
       Sgip_Deliver = packed record
         Deliver1:Sgip_Deliver1;
         Deliver2:Sgip_Deliver2;
       end;  
      //*********************Deliver_Resp命令
       Sgip_Deliver_Resp = packed record
         Result:byte;
         Reserve:packed array[1..8] of char;
       end;
      //**********************Report命令
       Sgip_Report = packed record
          SubmitSequenceNumber1:longword;
          SubmitSequenceNumber2:longword;
          SubmitSequenceNumber3:longword;
          ReportType:byte;
          UserNumber:packed array[1..21] of char;
          State:byte;
          ErrorCode:byte;
          Reserve:packed array[1..8] of char;
       end;
      //**********************Report_Resp命令
       Sgip_Report_Resp=packed record
          Result:byte;
          Reserve:packed array[1..8] of char;
       end;   
    //------------------------------------------------------------------------------
       _Bind = packed record
         header:Sgip_header;
         body:Sgip_Bind;
       end;
       _Bind_resp = packed record
         header:Sgip_header;
         body:Sgip_Bind_Resp;
       end;   _Unbind = packed record
         header:Sgip_header;
         body:Sgip_UnBind;
       end;
       _Unbind_Resp = packed record
         header:Sgip_header;
         body:Sgip_UnBind_Resp;
       end;   _Deliver = packed record
         header:Sgip_header;
         body:Sgip_Deliver;
       end;
       _Deliver_Resp = packed record
         header:Sgip_header;
         body:Sgip_Deliver_Resp;
       end;   _Submit = packed record
         header:Sgip_header;
         body:Sgip_Submit;
       end;
       _Submit_Resp = packed record
         header:Sgip_header;
         body:Sgip_Submit_Resp;
       end;
       
       _Report = packed record
         header:Sgip_header;
         body:Sgip_Report;
       end;
       _Report_Resp = packed record
         header:Sgip_header;
         body:Sgip_Report_Resp;
       end;
    implementationend.
      

  11.   

    强人啊,--》DelphiBird(爱你等于爱自己) 。
      

  12.   

    说一些procedure TClientThread.GenerateSequenceNo(var sn1, sn2, sn3: longword);
    begin
      //*************产生消息顺序号,依据SGIP协议
      sn1:=htonl(Sequence1);
      sn2:=htonl(strtoint(formatdatetime('mmddhhmmss',now())));
      if sn=4294967295 then sn:=0
      else inc(sn);
      sn3:=htonl(sn);
    end;1:
    >>if sn=4294967295 then sn:=0
    4294967295 = INFINITE,不要直接写数字,看不懂
    很多网关会有不同的最大值,所以,你得设个最大值: FMaxSequence
    还有,不要用StrToInt, StrToIntDef,习惯问题2:
    不要用SysUtils.StrPCopy
    自已写个: StrCopy(const Src: string; Buf: PChar; BufSize);
    TCP包字段的越界问题永远要考虑.3:
    写两函数: 
    SendPacket(Socket: TCustomWInSOcket; var Buf; BufSize: Integer): Boolean;
    RecvPacket(Socket: TCustomWInSOcket; var Buf; BufSize: Integer): Boolean;
    SGIP, CMPP, CNGP, SMGP, SMPP每个协议都规定了包头第一个字节是包长度,为什么不封装一个收包和发包过程? (记住考虑Socket ErrCode = 10035的错误)4:
    包结构既然很大部分都一样,为什么不考虑统一做一个处理包头结构,如:
    InitPacket(buf: PChar; Len, Cmd....)5:
    包长度既然用来用去,为什么不写个对象来封装这个包6:
    活动try finally
    而不是:
    CoInitialize(nil);
    if False then
    begin
      CoUninitialize;
      Exit;
    end;7:
    不要怕对常量的定义
    SGIP_OK = 0, SGIP_FAILED = 1,没人觉得会浪费8:
    SOCKET滑行窗口实现很简单:Count := 10;
    while Count > 0 do 
    begin
      SubmtData(GetSubmtData);
      WriteSubmitToBuffer; // Write Submit to Buffer写在SubmitData中,在socket.Send之前
      Dec(Count);
    end;while True do
    begin
      if not ReceivePacket(Packet) then break;
      InterpreterPacket(Packet);
    end;function  InterpreterPacket(Packet);
    begin
      if Packet.Cmd = SGIP_SUBMIT_RESP then
        DeleteSubmitWithSequenceId(Packet.SeqNo)
      else
        DoOther;
    end;9:
    SGIP的ActiveTest命令字为:
      SGIP_KEEPALIVE_VALUE = $10000001;
      SGIP_KEEPALIVE_RESP_VALUE = $10000010;10:
    我的费话太多:D
      

  13.   

    楼主,saoren提的这些都是很不错的建议,
    你可以根据这些建议,找出你代码中重复代码,一步步重构它们..要作异步处理仅重开线程不好的..
    SOCKET作异步有异步选择IO,和异步事件IO等.
    TClientSocket和TServerSocket的非阻塞方式是用异步选择IO实现,
    只是这种方式需要通过WINDOWS消息支持,也就是说它只工作在主线程.其实在主线程也不太坏,只是可能并发能力差了点.异步事件IO,是靠WINDOWS的EVENT支持实现的,DELPHI的TSocketconnection是用了它..
    你可以看看那些源码.里面包含一些技巧..
      

  14.   

    呵呵谢谢SAOREN的意见那不是在线程中不能使用异步了,没windows消息队列的维护了;
    地不到通知了
      

  15.   

    需要手机短信收发源码以及相关手机短信软件者,请登录我工作室网站下载:
    http://220.194.153.26:8089/noah/