最近一直在搞winsock api实现udp协议消息的接收,结果老有问题....
以下是部分代码:(根据api-guide的实例改编)
SelectOps = FD_READ Or FD_WRITE Or FD_CONNECT Or FD_CLOSE
If WSAAsyncSelect(sID, FWND,WINSOCKMSG, ByVal SelectOps) <> 0 Then
    waste = closesocket(sID)
    Exit Function
End If
MyHWND = SetWindowLong(FWND, GWL_WNDPROC, AddressOf MyFunc)
问题来啦:
1.调试的时候,我运行另外的程序隔2秒就往某个端口广播信息,可是我的消息处理函数根本就接收不到WINSOCKMSG消息...
2.WSAAsyncSelect函数申明的时候,各参数都有ByVal,可是调用的时候为什么还带上了?
大家帮帮忙啊~~~

解决方案 »

  1.   

    还有个问题:
    3.bind函数可以绑定端口、IP地址,setsockopt也可以设置。两个函数有什么差别啊?分别用在什么情况下的什么地方呢?
      

  2.   

    我也没怎么玩过这些API.....- -!
      

  3.   

    近来我也研究winsock API,也是关于UDP的,也遇到了问题,为何这样写就是发送不成功呢?
    Private Function WinSockUDPGetMAC(sIP As String)
    Dim sockfd As Long
    Dim t_NB As NetbiosNS
     'UDP发送包
    t_NB.buff(0) = &H0
    t_NB.buff(1) = &H0
    t_NB.buff(2) = &H0
    t_NB.buff(3) = &H0
    t_NB.buff(4) = &H0
    t_NB.buff(5) = &H1
    t_NB.buff(6) = &H0
    t_NB.buff(7) = &H0
    t_NB.buff(8) = &H0
    t_NB.buff(9) = &H0
    t_NB.buff(10) = &H0
    t_NB.buff(11) = &H0
    t_NB.buff(12) = &H20
    t_NB.buff(13) = &H43
    t_NB.buff(14) = &H4B
    Dim i As Integer
    For i = 15 To 44
    t_NB.buff(i) = &H41
    Next
    t_NB.buff(45) = &H0
    t_NB.buff(46) = &H0
    t_NB.buff(47) = &H21
    t_NB.buff(48) = &H0
    t_NB.buff(49) = &H1
    Dim aa As String
    aa = Hex(inet_addr("10.17.45.24"))
    If Len(aa) < 8 Then aa = 0 & aa
    Dim SocketBuffer As FSockAddrIn
        SocketBuffer.Sin_family = AF_INET
        SocketBuffer.Sin_port = htons(137)
        
        SocketBuffer.Sin_addr = CLng("&H" & aa)
        SocketBuffer.Sin_zero = String$(8, 0)sockfd = socket(AF_INET, SOCK_DGRAM, 0) 'UDP通信
    Dim Irc As Integer
    Irc = sendto(sockfd, t_NB, 50, 0, SocketBuffer, Len(SocketBuffer))
    If Irc = -1 Then MsgBox "错误"
    End Function
      

  4.   

    我的Sock类的其中一段代码,希望对你有用...
    Private Const SOCKET_MESSAGE  As Long = WM_USER + &H401
    Private Const lngEvents As Long = FD_READ Or FD_WRITE Or FD_ACCEPT Or FD_CONNECT Or FD_CLOSE
    ...
        '用钩子钩住窗口的信息,当窗口收到信息时用模块中的 SockInfoProc 来处理窗口所取得的所有信息
        SockWindowProc = GetWindowLong(SockWindowhWnd, GWL_WNDPROC)
        SetWindowLong SockWindowhWnd, GWL_WNDPROC, AddressOf SockInfoProc
        '让窗口有接受网络事件信息的能力
        ReturnLong = WSAAsyncSelect(SockRequestID, SockWindowhWnd, SOCKET_MESSAGE, lngEvents)
        
        '判断异步信息设置是否成功
        If ReturnLong <> 0 Then
            mvarState = sckError
            CancelERR = False
            RaiseEvent SockError(11003, "不可恢复的错误。", 0, "WinSock.Listen", "", 0, CancelERR)
            If CancelERR = False Then
                Err.Raise vbObjectError + 11003, "不可恢复的错误。", 11003, "", 0
            End If
            Exit Sub
        End If
    ...
      

  5.   

    我发现还是发的'UDP包有问题,但VB好象只能这样写了吧?为什么总提示类型不对呢?
    我这段代码是想修改网上关于利用UDP137发包获得主机信息的的DELPHI和C代码,把他改成VB版式的,但总还是不行,发包这段就错误了!
    现在我贴上那段DELPHI代码,供大家参考,希望对大家在winsock编程中有所帮助,也希望有能力的朋友,把这体段代码改成VB版的!
    {局域网IP搜索}
    unit U_FrmSearchNetIp;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls,
      WinSock,Forms, Dialogs, RXSpin, StdCtrls, ExtCtrls, Buttons, RXSplit,
      Grids, ComCtrls, RxRichEd;const
      WM_SOCK = WM_USER + 1;     {自定义windows消息}
      NBTPORT =  137;         {向对方的137端口发数据包(UDP包)}Type
      TTGroupNet=record {网络标识}
          IP:string;
          ComputerName:string;
          ComputerDes:string;
          NetGroup:string;
          NetMacCode:string;
      end;
    type
      TFrmSearchNetIp = class(TForm)
        Panel2: TPanel;
        Panel1: TPanel;
        Label1: TLabel;
        Label2: TLabel;
        Label3: TLabel;
        EdNetIP1: TEdit;
        EdNetIP2: TEdit;
        Panel3: TPanel;
        Panel4: TPanel;
        PageControl1: TPageControl;
        TabSheet1: TTabSheet;
        SgDispNetIP: TStringGrid;
        TabSheet2: TTabSheet;
        Panel5: TPanel;
        Panel6: TPanel;
        SBrnScanNetIP: TSpeedButton;
        SBtnStopScan: TSpeedButton;
        LabIP: TLabel;
        LabStartTime: TLabel;
        LabEndTime: TLabel;
        LabTime: TLabel;
        Label4: TLabel;
        TabSheet3: TTabSheet;
        procedure FormCreate(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
        procedure SBtnStopScanClick(Sender: TObject);
        procedure SBrnScanNetIPClick(Sender: TObject);
        procedure SgDispNetIPSelectCell(Sender: TObject; ACol, ARow: Integer;
          var CanSelect: Boolean);
        procedure SgDispNetIPDblClick(Sender: TObject);
      private
        { Private declarations }
        procedure ReadData(var Message: TMessage); message WM_SOCK;  {消息接送}
        Procedure ClearGrid();
        Procedure MakeGrid(Const IntIndex:integer=3);{排序}  public
        { Public declarations }
      end;{*******************************************************}
      TComread=class(TThread) {通讯线程}
      private
      public
       Tagg:integer;
      protected
        procedure Execute; override;
      end;
      {始化SOCKET}
      Procedure WinSockInital(Handle: HWnd);
      {关闭SOCKET}
      Procedure WinSockClose();
    const NbtstatPacket:array[0..49]of byte  {发送数据包}
          =($0,$0,$0,$0,$0,$1,
          $0,$0,$0,$0,$0,$0,$20,$43,$4b,
          $41,$41,$41,$41,$41,$41,$41,$41,
          $41,$41,$41,$41,$41,$41,$41,$41,
          $41,$41,$41,$41,$41,$41,$41,$41,
          $41,$41,$41,$41,$41,$41,$0,$0,$21,$0,$1);
    {*******************************************************}
    var
      FrmSearchNetIp: TFrmSearchNetIp;  TF_stop:boolean;  {停止}
      TempWSAData: TWSAData;
      sockfd:TSocket;     {Integer socket句柄}
      WAIT_ACK_EVENT:Thandle; {LongWord  句柄|}
      FSockAddrIn : TSockAddrIn;  IP_count,ComputerIP:integer;
      IP_end:     Dword;
      StartTickCount:DWORD ; {计数器}
      StopTickCount: DWORD ;  TGroupNet:array of TTGroupNet;{网络信息寄存}
      IntGridCol:integer;
      
    implementation{$R *.DFM}procedure TFrmSearchNetIp.FormCreate(Sender: TObject);
    begin
        IntGridCol:=0;
        {TRxRichEdit 去除64K的限制}
        RxRedDispinf.MaxLength := High(Integer) - 1024;
        {Grid清除 ClearGrid}
        ClearGrid;
    end;
    procedure TFrmSearchNetIp.FormClose(Sender: TObject;
      var Action: TCloseAction);
    begin
      TF_stop:=True;
      setlength(TGroupNet,0);
      {关闭SOCKET}
      WinSockClose();
    end;
    {停止扫描}
    procedure TFrmSearchNetIp.SBtnStopScanClick(Sender: TObject);
    begin
     TF_stop:=True;
    end;
      

  6.   

    {****************** SOCKET通讯  *****************}
    {始化SOCKET}
    Procedure WinSockInital(Handle: HWnd);
    begin
         { 1 初始化SOCKET}
         TF_stop:=false;
         if WSAStartup(2, TempWSAData)=1 then
         begin
           showmessage('Socket初始化出错');
           exit
         end;
         {若是用UDP通信,则用}
         sockfd:=Socket(AF_INET,SOCK_DGRAM,0);     FSockAddrIn.SIn_Family := AF_INET;
         FSockAddrIn.SIn_Port := htons(NBTPORT);  {137端口}    {Socket的信息传递--》From.Handle 窗体, FD_READ 在读就绪的时候, WM_SOCK 自定义消息号}
         WSAAsyncSelect(sockfd, Handle , WM_SOCK, FD_READ);
        {创建事件}
         WAIT_ACK_EVENT:=CreateEvent(nil,true,false,pchar('WAIT_ACK') );
         ResetEvent(WAIT_ACK_EVENT);
    end;
    {关闭SOCKET}
    Procedure WinSockClose();
    begin
       TF_stop:=True;
       CloseSocket(sockfd); {closesocket函数用来关闭一个描述符为sockfd套接字}
       WSACleanup;
       sleep(2);
    end;
    {****************** SOCKET通讯  *****************}
    {扫描开始}
    procedure TFrmSearchNetIp.SBrnScanNetIPClick(Sender: TObject);
    var
      DWx1,Dwx:Dword;
      IP,Str_Ip:string;
      Tcomr:TComread;
    begin
       RxRichEdit1.text:='';
       Setlength(TGroupNet,0);
       {始化SOCKET}
       WinSockInital(FrmSearchNetIp.Handle);   {清除Grid}
       ClearGrid;
       TF_stop:=false;
       IP:=trim(EdNetIP1.text);
       RxRedDispinf.Text :='';
       label4.Caption:='IP个数:'; 
       LabIP.caption:='';
       LabStartTime.caption:='开始时间:';
       LabEndTime.caption:='结束时间:';
       LabTime.caption:='扫描用时:';
       if Longword(inet_addr(pchar(IP)))=INADDR_NONE then
       begin
          Messagebox(Application.handle,pchar(IP + ' TP 出错'),'警告',MB_OK+MB_ICONERROR);
          exit;
       end;
       IP:=trim(EdNetIP2.text);
       if Longword(inet_addr(pchar(IP)))=INADDR_NONE then
       begin
          Messagebox(Application.handle,pchar(IP + ' TP 出错'),'警告',MB_OK+MB_ICONERROR);
          exit;
       end;
        IP:=trim(EdNetIP1.text);
        ComputerIP:=inet_addr(PChar(IP)) ;  // 192.168.0.1 ===>01 00 A8 C0
        str_ip:=inttohex(ComputerIP,8);    //01 00 A8 C0
        str_ip:=copy(str_ip,7,2)+copy(str_ip,5,2)+copy(str_ip,3,2)+copy(str_ip,1,2);   //==> C0 A8 00 01
        DWx:=strtoint('$'+str_ip); {转换成为一个长整形数}    str_ip:=inttohex(ComputerIP,8);
        str_ip:=inttostr(strtoint('$' + copy(str_ip,7,2)))
                    +'.' + inttostr(strtoint('$' + copy(str_ip,5,2)))
                    +'.' + inttostr(strtoint('$' + copy(str_ip,3,2)))
                    +'.' + inttostr(strtoint('$' + copy(str_ip,1,2)));
        EdNetIP1.text:=str_ip;  {允许输入 一个数值表示IP}    IP:=trim(EdNetIP2.text);
        ComputerIP:=inet_addr(PChar(IP)) ;  // 192.168.0.1 ===>01 00 A8 C0
        str_ip:=inttohex(ComputerIP,8);    //01 00 A8 C0
        str_ip:=copy(str_ip,7,2)+copy(str_ip,5,2)+copy(str_ip,3,2)+copy(str_ip,1,2);   //==> C0 A8 00 01
        DWx1:=strtoint('$'+str_ip);   {转换成为一个长整形数}    str_ip:=inttohex(ComputerIP,8);
        str_ip:=inttostr(strtoint('$' + copy(str_ip,7,2)))
                   +'.' + inttostr(strtoint('$' + copy(str_ip,5,2)))
                   +'.' + inttostr(strtoint('$' + copy(str_ip,3,2)))
                   +'.' + inttostr(strtoint('$' + copy(str_ip,1,2)));
        EdNetIP2.text:=str_ip;  {允许输入 一个数值表示IP}     if DWx1>Dwx then
         begin
            IP_count:=DWx1-Dwx;
            ComputerIP:=inet_addr(PChar(trim(EdNetIP1.text)));
            IP_end:=DWx1;
            label1.caption:='-->>';
         end
         else begin
            IP_count:=DWx-Dwx1;
            ComputerIP:=inet_addr(PChar(trim(EdNetIP2.text)));
            IP_end:=DWx;
            label1.caption:='<<--';
         end;    SBrnScanNetIP.Enabled :=false;  {屏蔽按键}
        Tcomr:=TComread.Create(True);
        StartTickCount:=GetTickCount;
        LabStartTime.caption:='开始时间:' + FloatToStr(StartTickCount);
        Tcomr.Resume ;  {开始线程}
    end;
    { TComread }
    {通讯线程}
    procedure TComread.Execute;
    var
       str_ip:string;
       IP_now:Dword;
       Procedure MakeEnd();
       begin
         FrmSearchNetIp.SBrnScanNetIP.Enabled :=True;
         StopTickCount:=GetTickCount;
         FrmSearchNetIp.LabEndTime.caption:='结束时间:' +FloatToStr(StopTickCount);
         FrmSearchNetIp.LabTime.caption:='扫描用时:' +FloatToStr(StopTickCount-startTickCount)+' mS';
         FrmSearchNetIp.label4.Caption:='IP个数:'+ inttostr(FrmSearchNetIp.SgDispNetIP.RowCount-1);
         FrmSearchNetIp.MakeGrid(3);
     {排序
     'TP地址'0  '计算机名称'1  '计算机描述' 2
     '网络组'3  '网卡MAC码'4
      MakeGrid(const IntIndex: integer=3);}
       end;
    begin  with FrmSearchNetIp do
      begin
         str_ip:=inttohex(ComputerIP,8);    //01 00 A8 C0
         str_ip:=copy(str_ip,7,2)+copy(str_ip,5,2)+copy(str_ip,3,2)+copy(str_ip,1,2);   //==> C0 A8 00 01
         IP_now:=strtoint('$'+str_ip);      while IP_end>=IP_now do         ////IP_end==> C0 A8 00 01
          begin
             if TF_stop=True then
             begin
              MakeEnd();
              {关闭SOCKET}
              WinSockClose();
              exit;
             end;
             str_ip:=inttohex(ComputerIP,8);
             str_ip:=inttostr(strtoint('$' + copy(str_ip,7,2)))
                    +'.' + inttostr(strtoint('$' + copy(str_ip,5,2)))
                    +'.' + inttostr(strtoint('$' + copy(str_ip,3,2)))
                    +'.' + inttostr(strtoint('$' + copy(str_ip,1,2)));
             LabIP.caption:=str_ip;  {目前扫描的IP}         FSockAddrIn.SIn_Addr.S_addr := ComputerIP;//inet_addr(pchar(IP));
             str_ip:=inttohex(ComputerIP,8);    //01 00 A8 C0
             str_ip:=copy(str_ip,7,2)+copy(str_ip,5,2)+copy(str_ip,3,2)+copy(str_ip,1,2);   //==> C0 A8 00 01
             str_ip:=inttohex( strtoint(('$' + str_ip))+1,8);      //==> 加一C0 A8 00 02
             IP_now:=strtoint('$'+str_ip);
             str_ip:=copy(str_ip,7,2)+copy(str_ip,5,2)+copy(str_ip,3,2)+copy(str_ip,1,2);  //==>02 00 A8 C0
             ComputerIP:=strtoint('$'+str_ip);
             sendto(sockfd, NbtstatPacket,50, 0, FSockAddrIn, sizeof(FSockAddrIn));
             //发送数据后
             waitforsingleobject(WAIT_ACK_EVENT,trunc(  RxSEdDelay.Value)); // 等待事件变成有信号
             ResetEvent(WAIT_ACK_EVENT);      // 设为没有信号
          end;
          MakeEnd();
      end;
     {关闭SOCKET}
      WinSockClose();
    end;
      

  7.   


    { TFrmSearchNetIp }
    {消息接送}
    procedure TFrmSearchNetIp.ReadData(var Message: TMessage);
    var
       Buffer: Array [1..500] of byte;
       flen,len,i,j,pos,name_num: integer;
       Event: word;
       IP:string;
       str_tp,str:string;
       str_list_IP,str_list_name,str_list_disp,str_list_group,str_list_MAC:string;
       StrTp:string;
    begin
         flen:=sizeof(FSockAddrIn);
         Event := WSAGetSelectEvent(Message.LParam);
         if Event = FD_READ then
         begin
              len := recvfrom(sockfd, buffer, sizeof(buffer), 0, FSockAddrIn, flen);
              if len> 0 then
              begin
                //FSockAddrIn.sin_addr.S_un_b.s_b1
                with FSockAddrIn.sin_addr.S_un_b  do
                  IP:=format('%d.%d.%d.%d',[ord(s_b1),ord(s_b2),ord(s_b3),ord(s_b4)]);
                  str_list_IP:=IP;
                  //数据分析
                  name_num:=0;
                  str_tp:='';
          for i:=1 to len do
          begin
            if((buffer[i]=$21)and(buffer[i+1]=$00)and(buffer[i+2]=$01)) then
                    begin
                name_num:=buffer[i+9];
                break;
            end;
          end;
          if name_num=0 then exit;
          pos:=i+10;
                  str:='';
          for i:=pos to (pos+18*name_num-1) do
          begin
             if (((i-pos)mod 18) =0) then
             begin
               for j:=0 to 14 do
               begin
                 if trim(char(buffer[i+j]))='' then buffer[i+j]:=ord(' ');
                 str:=str+char(buffer[i+j]);
               end;
               if (buffer[i+16] and $80)=$80 then
               begin
                          if buffer[i+15]=$0 then str_list_GROUP:=trim(str);  //网络组
                  str:=str+format('<%x>',[buffer[i+15]]);
          str:=str+'<GROUP>';
       end
       else begin
                       if buffer[i+15]=$20 then str_list_name:=trim(str) //计算机名
               else
               if buffer[i+15]=$3 then str_list_disp:=trim(str);//计算机说明
            str:=str+format('<%x>',[buffer[i+15]]);
            str:=str+'<UNIQUE>';
       end;
        str_tp:=str_tp + str +#13+#10;
        str:='';
     end;
          end;
          for i:=0 to 5 do
          begin
              str:=str+format('%.2x.',[buffer[i+pos+18*name_num]]);
          end;
          delete(str,length(str),1);
                  str_list_MAC:=trim(str); //网卡的MAC码
          str:='MAC:     '+str;
                  str_tp:=str_tp + str + #13+#10;
                  {网络信息}
                  RxRedDispinf.Text :=RxRedDispinf.Text +IP +  #13+#10+  str_tp+ #13+#10;
                  {Grid}
                  I:=SgDispNetIP.RowCount;
                  if I=2 then
                  begin
                     if trim(SgDispNetIP.Cells[0,1])<>'' then
                     begin
                        Inc(i);
                        SgDispNetIP.RowCount:=I;
                     end;
                  end
                  else begin
                       Inc(i);
                       SgDispNetIP.RowCount:=I;
                  end;
                  Dec(i);
                  SgDispNetIP.Cells[0,i]:=str_list_IP;//'TP地址'
                  SgDispNetIP.Cells[1,i]:=str_list_name;//'计算机名称'
                  SgDispNetIP.Cells[2,i]:=str_list_disp;//'计算机描述'
                  SgDispNetIP.Cells[3,i]:=str_list_GROUP;//'网络组'
                  SgDispNetIP.Cells[4,i]:=str_list_MAC;//'网卡MAC码'
                  {
                  RichEdit1.Text :=RichEdit1.Text + str_list_IP + ' ' + str_list_name + '  ' +
                  str_list_disp + '  ' + str_list_GROUP +'    '  + str_list_MAC+ #13+#10
                  }
                  setlength(TGroupNet,high(TGroupNet)+2);
                  TGroupNet[high(TGroupNet)].IP:=str_list_IP;//'TP地址'
                  TGroupNet[high(TGroupNet)].ComputerName :=str_list_name;//'计算机名称'
                  TGroupNet[high(TGroupNet)].ComputerDes:=str_list_disp;//'计算机描述'
                  TGroupNet[high(TGroupNet)].NetGroup:=str_list_GROUP;//'网络组'
                  TGroupNet[high(TGroupNet)].NetMacCode :=str_list_MAC;//'网卡MAC码'              StrTp:=str_list_IP + '   ' +str_list_name+ '   ' +
                    str_list_disp + '   ' + str_list_GROUP + '   ' +
                    str_list_MAC;
                  RxRichEdit1.Lines.Add(StrTp);
              end;
              SetEvent(WAIT_ACK_EVENT);//有信号
         end;
    end;
    {Grid清除 ClearGrid}
    procedure TFrmSearchNetIp.ClearGrid;
    begin
       SgDispNetIP.RowCount:=2;
       SgDispNetIP.Rows[1].Text:='';
       SgDispNetIP.Cells[0,0]:='TP地址' ;
       SgDispNetIP.Cells[1,0]:='计算机名称' ;
       SgDispNetIP.Cells[2,0]:='计算机描述' ;
       SgDispNetIP.Cells[3,0]:='网络组' ;
       SgDispNetIP.Cells[4,0]:='网卡MAC码' ;
    end; 
      

  8.   

    试了下,我觉得问题可能不是处在这里
    问题可能在bind函数,函数返回值虽然是0,但是我用超级兔子的进程管理器检查一下,已经使用的端口列表里面根本就没有我绑定的端口...
    这是怎么回事呢???
    还有,使用winsock控件的时候会被windows防火墙拦截,但是调用api就没有,是因为本来就不会被拦截,还是因为我的api调用不成功呢?可是我的函数返回值都表示很成功啊...
      

  9.   

    我发现这个函数WSAGetSelectEvent(Message.LParam)不知怎么声明,API中没有找到,网上也没找彼此函数的声明,但却用了很多!哪个高手给解释一下吧! 
      

  10.   

    应该是bind的问题,udp也是要bind端口和IP的,这个很多人都会忽略。xp+sp2下如果绑定成功的话系统防火墙是一定会问你的(同一个进程只问一次),所以如果你netstat -an 没有看到你的端口,就一定是绑定失败了。仔细检查一下bind的代码吧。
      

  11.   

    sendto(sockfd, NbtstatPacket,50, 0, FSockAddrIn, sizeof(FSockAddrIn));
    Copy后到这里出错,不理解