要求api写的udp通信(服务器和客户端相互发送数据)原码,服务器和客户端啊!希望可以点点适当的注释,万分的感谢!运行成功马上给分!

解决方案 »

  1.   

    UDP我就是搞不懂,D6自带的UDPSock就是用不了。。谁能告诉我。。
      

  2.   

    自己写了个服务器端的,好象问题多多!大家帮我改改
    var
      Form1: TForm1;
      servsock:tsocket;
      servaddr,fromaddr:tsockaddr;implementation{$R *.dfm}procedure TForm1.FormCreate(Sender: TObject);
    var wsaData:TwsaData;
    begin
    if WSAStartup (makeword(2,2), wsaData)<>0 then // WSAStartup返回值为0表示成功
     begin
     messagebox(application.handle,'无法启动winsock动态连接库!','警告',MB_OK or MB_APPLMODAL or MB_ICONWARNING);
     Application.Terminate;
     end;end;procedure TForm1.N2Click(Sender: TObject);beginservsock:=socket(af_inet,sock_dgram,ipproto_udp);
    if servSock=INVALID_SOCKET then
      begin
      messagebox(application.handle,'无法创建句柄!','警告',MB_OK or MB_APPLMODAL or MB_ICONWARNING);
      exit;
      end;
    servaddr.sin_family:=af_inet;
    servaddr.sin_addr.S_addr:=inet_addr(pchar('127.0.0.1'));
    servaddr.sin_port:=htons(5150);
    if bind(servsock,servaddr,sizeof(servaddr))=SOCKET_ERROR then
      begin
       messagebox(application.handle,'绑定地址错误!','警告',MB_OK or MB_APPLMODAL or MB_ICONWARNING);
       exit;
      end;
    statusbar1.SimplePanel:=true;
    statusbar1.SimpleText:='网络服务器开始运行';end;procedure TForm1.N3Click(Sender: TObject);
    begin
    closesocket(servsock);
    wsacleanup;
    statusbar1.SimpleText:='网络服务器开始关闭';
    end;procedure TForm1.Button1Click(Sender: TObject);
    var recvbuf: pchar ;
        relong,fromsize:integer;
        re:boolean;
    begin
     recvbuf:='';
     getmem(recvbuf,1024);
    //fromsize:=sizeof(fromaddr);
    re:=true;
    while re do
    begin
    relong:=recvfrom(servsock,recvbuf,1024,0,fromaddr,fromsize);
    if relong=SOCKET_ERROR then
      statusbar1.SimpleText:='接收错误: '+inttostr(WSAGetLastError)
       else
          if relong=0 then
          statusbar1.SimpleText:='错误:'+inttostr(WSAGetLastError)
          else
          begin
          memo1.Text:=recvbuf;
          edit1.Text:=inttostr(relong);
          end;
     end;
     freemem(recvbuf);end;
      

  3.   

    我大致看了看,不知道你要改什么地方?  re:=true;
      while re do ----〉在这个无限循环里接收数据,处理的不太合理,若是阻塞方式的套接字要另外开一个线程,循环里加上Sleep函数。另外就是要处理好一个 recvfrom 没有收到完整的一个包的情况,毕竟不是控件这些都要自己处理的。
      

  4.   

    有人说要我用select模型啊!
    我大致看了看,不知道你要改什么地方(编译确实通过了的,但是没的实际效果)
    这个程序运行后无法接受到客户端发送的数据!
    thisisyjs(只是一种感觉) 大哥,能不能和你在qq上聊聊啊!
      

  5.   

    用UDP发送广播到局域网的1434端口,并侦听收到的信息,用API函数怎么来写。我的邮箱: [email protected]可以帮忙的,我会开贴送分
      

  6.   

    其实我也不是特别明白,讨论讨论倒是可以,我用网易泡泡,id: [email protected]
    如果要先调通的话,可以一方用控件,比如调服务器端程序客户端先用 TNMUDP,看能不能通。
      

  7.   

    封装成类的源码要不要?全部源码在:http://mental.mentsu.com/down/dev/msocket12.zip(*
        基本的 WinSock 类,包含了 TCP/UDP 共有的部分,是一个抽象基类,
        其 Open 成员为纯虚
    *)
      TMCustomSocket = class(TObject)
      private
        FSocket  : TSocket;    //  WinSock Handle
        FLocal   : TSockAddr;  //  Local Address Info
        FRemote  : TSockAddr;  //  Remote Address Info(be filled after some operate)
        FLocHost : String;     //  Local Host Name  \_ be filled by
        FLocAddr : String;     //  Local IP Address /  GetLocalHostAddr procedure
        FTimeOut : Integer;    //  Socket time out, by miliseconds    Procedure GetLocalHostAddr;
        Function  GetActive : Boolean;
        Procedure SetActive( aActive : Boolean );
        Function  GetLocalHost : String;
        Function  GetLocalAddr : String;
        Function  GetLocalPort : Integer;
        Procedure SetLocalPort( aPort : Integer );
        Function  GetRemoteHost : String;
        Function  GetRemoteAddr : String;
        Procedure SetRemoteHostAddr( aHostAddr : String );
        Function  GetRemotePort : Integer;
        Procedure SetRemotePort( aPort : Integer );  protected
        Procedure SetTimeOut( aTimeOut : Integer ); Virtual;    Procedure Open; Virtual; Abstract;
        Procedure Close; Virtual;  public
        Constructor Create;
        Destructor  Destroy; Override;    function  WaitForData : Boolean;    Property Socket     : TSocket Read FSocket;
        Property Active     : Boolean Read GetActive     Write SetActive;
        Property LocalHost  : String  Read GetLocalHost;
        Property LocalAddr  : String  Read GetLocalAddr;
        Property LocalPort  : Integer Read GetLocalPort  Write SetLocalPort;
        Property RemoteHost : String  Read GetRemoteHost Write SetRemoteHostAddr;
        Property RemoteAddr : String  Read GetRemoteAddr Write SetRemoteHostAddr;
        Property RemotePort : Integer Read GetRemotePort Write SetRemotePort;
        Property TimeOut    : Integer Read FTimeOut      Write SetTimeOut;
      end; (*
        UDP 通信类,实现纯虚成员 Open 和用于收发消息的两个成员:
        SendMessage/RecvMessage
      *)
      TMUDPSocket = class( TMCustomSocket )
      Public
       Constructor Create;
        Destructor  Destroy; Override;    Procedure Open; Override;
        Procedure Close; Override;
        Procedure SendString( aMessage : String );
        Function  RecvString : String;
      End;//  TMCustomSocket 类的实现//  构造函数,初始化各成员
    Constructor TMCustomSocket.Create;
    Begin
    Inherited Create;
        FSocket                 := INVALID_SOCKET;
        FLocal.sin_family       := AF_INET;
        FLocal.sin_addr.S_addr  := htonl( INADDR_ANY );
        FLocal.sin_port         := htons( 0 );
        FRemote.sin_family      := AF_INET;
        FRemote.sin_addr.S_addr := htonl( INADDR_ANY );
        FRemote.sin_port        := htons( 0 );
        FLocHost                := '';
        FLocAddr                := '';
        FTimeOut                := 1000;
    End;//  析构函数,析构前关闭 Socket
    Destructor TMCustomSocket.Destroy;
    Begin
    Close;
        Inherited Destroy;
    End;//  如果 Socket 打开的话,关闭它
    Procedure TMCustomSocket.Close;
    Begin
    If ( FSocket <> INVALID_SOCKET ) Then
        Begin
         closesocket( FSocket );
            FSocket := INVALID_SOCKET;
        End;
    End;//  等待接收数据
    function TMCustomSocket.WaitForData : Boolean;
    var
        FDSet   : TFDSet;
        TimeVal : TTimeVal;
    begin
        TimeVal.tv_sec  := FTimeout div 1000;
        TimeVal.tv_usec := (FTimeout mod 1000) * 1000;
        FD_ZERO(FDSet);
        FD_SET(FSocket, FDSet);
        Result := select(0, @FDSet, nil, nil, @TimeVal) > 0;
    end;//  取得本地 IP Address & Host Name ,只在此两项为空时执行一次
    Procedure TMCustomSocket.GetLocalHostAddr;
    Var
    buf  : Array [0..63] Of Char;
        phe  : PHostEnt;
        ppia : PAPInAddr;
    Begin
    If ( ( FLocHost = '' ) OR ( FLocAddr = '' ) ) Then
        Begin
         gethostname( buf, sizeof( buf ) );
            FLocHost := buf;
            phe := gethostbyname( buf );
            If ( phe = Nil ) Then
             Exit;
            ppia := PAPInAddr( phe^.h_addr_list );
            FLocAddr := inet_ntoa( ppia^[0]^ );
        End;
    End;//  判断 Socket 是否打开
    Function TMCustomSocket.GetActive : Boolean;
    Begin
    Result := ( FSocket <> INVALID_SOCKET );
    End;//  打开/关闭 Socket
    Procedure TMCustomSocket.SetActive( aActive : Boolean );
    Begin
        If ( aActive <> Active ) Then
        Begin
         If ( aActive ) Then
                Open
            Else
             Close;
        End;
    End;//  取得本机 Host Name
    Function TMCustomSocket.GetLocalHost : String;
    Begin
    If ( FLocHost = '' ) Then
         GetLocalHostAddr;
        Result := FLocHost;
    End;//  取得本机 IP Address
    Function TMCustomSocket.GetLocalAddr : String;
    Begin
    If ( FLocAddr = '' ) Then
         GetLocalHostAddr;
        Result := FLocAddr;
    End;//  取得本机端口
    Function TMCustomSocket.GetLocalPort : Integer;
    Begin
    Result := ntohs( FLocal.sin_port );
    End;//  设置本机端口
    Procedure TMCustomSocket.SetLocalPort( aPort : Integer );
    Begin
    If ( Active ) Then
         Raise Exception.Create( 'This socket is opened, cannot change localport!' );
        FLocal.sin_port := htons( aPort );
    End;//  取远程主机名
    Function TMCustomSocket.GetRemoteHost : String;
    Var
    phe : PHostEnt;
    Begin
    Result := '';
    phe := gethostbyaddr( @( FRemote.sin_addr.S_addr ), 4, AF_INET );
        If ( phe <> Nil ) Then
         Result := phe^.h_name;
    End;//  取远程主机地址
    Function TMCustomSocket.GetRemoteAddr : String;
    Begin
    Result := inet_ntoa( FRemote.sin_addr );
    End;//  设置远程主机名/地址,根据参数是否为 IP 地址自动设置
    Procedure TMCustomSocket.SetRemoteHostAddr( aHostAddr : String );
    Var
    phe : PHostEnt;
    Begin
    aHostAddr := Trim( aHostAddr );
        If ( IsIPAddr( aHostAddr ) ) Then
         FRemote.sin_addr.S_addr := inet_addr( PChar( aHostAddr ) )
        Else
        Begin
         phe := gethostbyname( PChar( aHostAddr ) );
            If ( phe <> Nil ) Then
             FRemote.sin_addr := PAPInAddr( phe^.h_addr_list )^[0]^;
        End;
    End;//  取远程端口号
    Function TMCustomSocket.GetRemotePort : Integer;
    Begin
    Result := ntohs( FRemote.sin_port );
    End;//  设置远程端口号
    Procedure TMCustomSocket.SetRemotePort( aPort : Integer );
    Begin
    FRemote.sin_port := htons( aPort );
    End;//  设置超时时间
    Procedure TMCustomSocket.SetTimeOut( aTimeOut : Integer );
    Begin
    If ( aTimeOut <> FTimeOut ) Then
        Begin
    FTimeOut := aTimeOut;
    If ( FSocket <> INVALID_SOCKET ) Then
         //  SO_RCVTIMO = $1006
         SocketError( setsockopt( FSocket, SOL_SOCKET, $1006, @aTimeOut, SizeOf( aTimeOut ) ) );
        End;
    End;
      

  8.   

    //  TMUDPSocketConstructor TMUDPSocket.Create;
    Begin
    Inherited Create;
    End;Destructor TMUDPSocket.Destroy;
    Begin
    Inherited Destroy;
    End;//  打开一个 UDP Socket 并绑定本机地址/端口
    Procedure TMUDPSocket.Open;
    Begin
    If ( FSocket = INVALID_SOCKET ) Then
        Begin
            FSocket := WinSock.socket( PF_INET, SOCK_DGRAM, 0 );
            If ( FSocket = INVALID_SOCKET ) Then
             SocketError( SOCKET_ERROR );
            SocketError( bind( FSocket, FLocal, SizeOf( FLocal ) ) );
        End;
    End;//  关闭 UDP Socket
    procedure TMUDPSocket.Close;
    begin
    Inherited Close;
    end;//  发送一个 UDP 消息
    //  aMessage 为要发送的消息串
    Procedure TMUDPSocket.SendString( aMessage : String );
    Var
    nSize, nError : Integer;
        buf, p : PByte;
    Begin
    If ( FSocket <> INVALID_SOCKET ) Then
        Begin
         nSize := Length( aMessage ) + 1;
            GetMem( buf, nSize );                            //  分配缓冲区
            Try
                ZeroMemory( buf, nSize );
                StrCopy( PChar( buf ), PChar( aMessage ) );
                p := buf;
                nError := sendto( FSocket, nSize, SizeOf( nSize ), 0, FRemote, SizeOf( FRemote ) );
                If ( nError <> SizeOf( nSize ) ) Then
                    Raise Exception.Create( crsErrInvSize );
                While ( nSize > 0 ) Do
                Begin
                    nError := cnMsgSize;
                    If ( nSize < cnMsgSize ) Then
                        nError := nSize;
                    nError := sendto( FSocket, p^, nError, 0, FRemote, SizeOf( FRemote ) );
                    If ( nError > 0 ) Then
                    Begin
                        Inc( p, nError );
                        nSize := nSize - nError;
                    End
                    Else
                        Raise Exception.Create( crsErrSendData );
                End;
            Finally
                FreeMem( buf );
            End;
        End;
    End;//  接收 UDP 消息
    //  返回收到的消息串
    Function TMUDPSocket.RecvString : String;
    Var
    nSize, nError, nFromLen : Integer;
        buf, p : PByte;
    Begin
    Result := '';
    If ( FSocket <> INVALID_SOCKET ) Then
        Begin
            nFromLen := SizeOf( FRemote );
         If ( Not WaitForData ) Then                      //  等待数据到达
             Raise EMSocket.Create( crsErrRecvTimeout + SocketErrorCode );
            nError := recvfrom( FSocket, nSize, SizeOf( nSize ), 0, FRemote, nFromLen );
            SocketError( nError );
            If ( nError <> SizeOf( nSize ) ) Then
                Raise Exception.Create( crsErrInvSize );
            GetMem( buf, nSize );                            //  分配缓冲区
            Try
                FillMemory( buf, nSize, 0 );
                p := buf;
                While ( nSize > 0 ) Do
                Begin
                    nError := cnMsgSize;
                    If ( nSize < cnMsgSize ) Then
                        nError := nSize;
                    If ( Not WaitForData ) Then              //  等待数据到达
                        Raise EMSocket.Create( crsErrRecvTimeout + SocketErrorCode );
                    nError := recvfrom( FSocket, p^, nError, 0, FRemote, nFromLen );
                    SocketError( nError );
                    If ( nError > 0 ) Then
                    Begin
                        Inc( p, nError );
                        nSize := nSize - nError;
                    End
                    Else
                        Raise Exception.Create( crsErrRecvData );
                End;
                Result := PChar( buf );
            Finally
                FreeMem( buf );
            End;
        End;
    End;
      

  9.   

    我本来是用TNMUDP的,很简单也可以接受数据,但是对方用了一个结构(vc包括2个数组)发送数据,我这里用TNMUDP接受数据有问题. 因为 TNMUDP的revebuff 函数的接收参数是一个数组类型,这个接收就不完整!
      

  10.   

    unit udp;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, winsock,
      StdCtrls;const
      WM_SOCK = WM_USER + 1;     //自定义windows消息
      UDPPORT = 646;            //设定UDP端口号type
      Tfrmmain = class(TForm)
        Button1: TButton;
        Edit1: TEdit;
        Memo1: TMemo;
        Edit2: TEdit;
        Label1: TLabel;
        Label2: TLabel;
        Label3: TLabel;
        procedure FormCreate(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
        s: TSocket;
        addr: TSockAddr;
        FSockAddrIn : TSockAddrIn;
            //利用消息实时获知UDP消息
        procedure ReadData(var Message: TMessage);
                message WM_SOCK;
      public
        { Public declarations }
        procedure SendData(Content: String);
      end;var
      frmmain: Tfrmmain;implementation{$R *.DFM}procedure Tfrmmain.FormCreate(Sender: TObject);
    var
       TempWSAData: TWSAData;
       //optval: integer;
    begin
    // 初始化SOCKET
         if WSAStartup($101, TempWSAData)=1 then
            showmessage('StartUp Error!');     s := Socket(AF_INET, SOCK_DGRAM, 0);
         if (s = INVALID_SOCKET) then   //Socket创建失败
         begin
              showmessage(inttostr(WSAGetLastError())+'  Socket创建失败');
              CloseSocket(s);
    //          exit;
         end;
         //发送方SockAddr绑定
         addr.sin_family := AF_INET;
         addr.sin_addr.S_addr := INADDR_ANY;
         addr.sin_port := htons(UDPPORT);
         if Bind(s, addr, sizeof(addr)) <> 0  then
           begin
             showmessage('bind fail');
           end;
         {optval:= 1;
         if setsockopt(s,SOL_SOCKET,SO_BROADCAST,pchar(@optval),sizeof(optval)) = SOCKET_ERROR then
         begin
           showmessage('无法进行UDP广播');
         end;}
         WSAAsyncSelect(s, frmmain.Handle , WM_SOCK, FD_READ);
         //接收端SockAddrIn设定
         FSockAddrIn.SIn_Family := AF_INET;
         FSockAddrIn.SIn_Port := htons(UDPPORT);
         label3.Caption := '端口:'+inttostr(UDPPORT);
    end;procedure Tfrmmain.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
        CloseSocket(s);
    end;procedure Tfrmmain.ReadData(var Message: TMessage);
    var
       buffer: Array [1..4096] of char;
       len: integer;
       flen: integer;
       Event: word;
       value: string;
    begin
         flen:=sizeof(FSockAddrIn);
         FSockAddrIn.SIn_Port := htons(UDPPORT);
         Event := WSAGetSelectEvent(Message.LParam);
         if Event = FD_READ then
         begin
              len := recvfrom(s, buffer, sizeof(buffer), 0, FSockAddrIn, flen);
              value := copy(buffer, 1, len);
              Memo1.Lines.add(value)
         end;
    end;procedure Tfrmmain.SendData(Content: String);
    var
       value{,hostname}: string;
       len: integer;
    begin     FSockAddrIn.SIn_Addr.S_addr := inet_addr(pchar(Edit1.text)); //INADDR_BROADCAST;   //INADDR_BROADCAST = -1 ?
         value := Content;
         len := sendto(s, value[1], Length(value), 0, FSockAddrIn, sizeof(FSockAddrIn));
         if (WSAGetLastError() <> WSAEWOULDBLOCK) and (WSAGetLastError() <> 0) then
            showmessage(inttostr(WSAGetLastError()));
         if len = SOCKET_ERROR then
            showmessage('send fail');
         if len <> Length(value) then
            showmessage('Not Send all');
    end;procedure Tfrmmain.Button1Click(Sender: TObject);
    begin
         senddata(Edit2.text);
    end;end.
      

  11.   

    to skyingandy(吃素的小狼)
    因为 TNMUDP的revebuff 函数的接收参数是一个数组类型,这个接收就不完整!怎么会收不完整呢?!
    是你方法不对。