本帖最后由 yklovelife 于 2009-11-30 15:14:36 编辑

解决方案 »

  1.   

    源码如下:unit Main;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, Buttons,WinSock;
    type
      TForm1 = class(TForm)
        edtIP: TEdit;
        btnSend: TBitBtn;
        mmo1: TMemo;
        edtMsg: TEdit;
        lblIP: TLabel;
        mmo2: TMemo;
        procedure btnSendClick(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
       procedure ServerReader(s:TSocket);
    var
      Form1: TForm1; 
      sockSrv:TSocket;//接受线程 
      buf:array[0..100] of Char; 
      trdHandle:THandle;//当前线程句柄
      trdOutHand:THandle;//Out Handle
    implementation
    uses SockRdTrd;
    {$R *.dfm}procedure TForm1.FormCreate(Sender: TObject);
    var
      addrClient:sockaddr_in;   
      sendSize:Integer;//SIZE OF addrClient 
      acThreadID:DWORD;//线程ID
      wsd:TWSAData;
      addrSrv:sockaddr_in;
      nRet:Integer;//返回的结果
      wVersionRequested:Word;//WinSock版本
    begin
      wVersionRequested:=MakeWord(2,1);
      if WSAStartup(wVersionRequested,wsd)<>0 then //加载DLL
         begin
           ShowMessage('加载失败!');
           Exit;
         end;
      //创建套接字
      sockSrv:=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
      if sockSrv=INVALID_SOCKET then
      begin
        ShowMessage('创建失败!');
        WSACleanup;
        Exit;
      end;
      //设置服务器地址
      ZeroMemory(@buf[0],BUF_SIZE);
      addrSrv.sin_addr.S_addr:=htonl(INADDR_ANY);
      addrSrv.sin_family:=AF_INET;
      addrSrv.sin_port:=htons(5000);
      //绑定套接字
      nRet:=bind(sockSrv,addrSrv,SizeOf(addrSrv));
      if Socket_Error=nRet then
      begin
        ShowMessage('bind failed');
        closesocket(sockSrv);
        WSACleanup;
        Exit;
      end;
      sendSize:=SizeOf(addrClient);
      trdHandle:=CreateThread(nil,0,@ServerReader,@sockSrv,0,acThreadID);
    end;
    procedure ServerReader(s:TSocket);
    var
      nRet:Integer;//返回结果
      addrClient:sockaddr_in;
      sendSize:Integer;
      conAddr:string;//CLIENT IP
    begin
      // 从客户端接收数据nonzero
      sendSize:=SizeOf(addrClient);
      //WaitForSingleObject(trdHandle,1000);
      while GetExitCodeThread(trdHandle,trdOutHand) do
      begin
        nRet := recvfrom(sockSrv,buf,SizeOf(buf),0,addrClient,sendSize);
        if nRet>0 then
        begin//打印来自客户端发送的数据
          conAddr:=inet_ntoa(addrClient.sin_addr);
          Form1.mmo1.Lines.Add('来自 '+conAddr+'的消息: '+buf);
        end;   
      end;
    end;
    //Client
    procedure TForm1.btnSendClick(Sender: TObject);
    var
      wsd:TWSAData;
      s:TSocket;
      nRet,sockClient:Integer;
      buf:array[0..100] of Char;
      servAddr:sockaddr_in;
      nServAddrLen:Integer;
    begin
      //加载DLL
      if WSAStartup(MakeWord(2,1),wsd)<>0 then
      begin
        ShowMessage('WSAStartup failes!');
        Exit;
      end;
      //初始化套接字
      s:=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
      if S=INVALID_SOCKET then
      begin
        ShowMessage(Format('socket() failed ,Error Code :%d',[WSAGetLastError]));
        WSACleanup;
        Exit;
      end;
      sockClient:=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
      ZeroMemory(@buf[0],100); //为什么要填补内存块
      //设置服务器地址
      servAddr.sin_family:=AF_INET;
      servAddr.sin_addr.S_addr:=inet_addr(PChar(edtIP.Text));
      servAddr.sin_port:=htons(5000);
      //向服务器发送数据
      nServAddrLen:=SizeOf(servAddr);
      StrCopy(buf,PChar(edtMsg.Text));
      nRet:=sendto(sockClient,buf,100,0,servAddr,nServAddrLen);
      if nRet=SOCKET_ERROR then
      begin
        ShowMessage(Format('recvfrom() failed',[WSAGetLastError]));
        closesocket(s);
        WSACleanup();
        Exit;
      end;
      closesocket(s);
      WSACleanup();
    end;
    end.
      

  2.   

    直接这样不是创建一个线程吗?
    CreateThread(nil,0,@ServerReader,@sockSrv,0,acThreadID); 
    我自己也不知道。请指点下。
      

  3.   

    你服务端始终使用的是第一次连接大客户端socket,所以只能收到第一个人的,你需要维护一个客户端列表,然后创建一个线程,去循环扫描客户端socket列表,这需要用到WinSock.select功能去选择一个连接,然后读取这个链接发送的数据
      

  4.   

    代码写的。。初始化了俩次
    1.现在问题出在不能实现多客户端连接发送消息,貌似我创建的线程没起作用,或者我的写法本身有问题 
    线程开始就运行完估计你都还没发送包出去
    自己4.不用任何控件,要用线程,但不能使用线程类Thread。
    却到线程里   Form1.mmo1.Lines.Add('来自 '+conAddr+'的消息: '+buf); 
    明明只是这只是个简单的socket程序,你把接收代码放到发送后就可以了
    你自己估计连客户端和服务端都没清楚,
      

  5.   

    你说的思路我大体明白了,但请问下,具体该如何用DEMO实现,伪代码也可以,有个小小的提示就好,
    1.需要维护一个客户端列表
    2.然后创建一个线程,去循环扫描客户端socket列表
    能否帮我写几句关键代码。
      

  6.   

    你要UDP的还是TCP的?TCP的写得比较简单,只是一个模型。UDP的是网上的一个例子,功能比较全,
    TCP的是一对多的,UDP的是点对点的
      

  7.   

    我需要的是UDP的,我就需要的是点对点的效果。
      

  8.   

    请教下 "稻草人"你给我发的程序,server和client分别定义了一个同样的 消息过程。
    procedure WMSOCKET(var msg: TMessage);message WM_SOCKET;
    而且所有数据包,都是在这个 procedure中完成的,请问这是 如何 通信的。WMSOCKET 并 没有在任何地方被调用。
      

  9.   

    你之前的一个贴子,我贴了代码,并且作了详细的注释及说明,你干嘛不认真看一下?
      if SOCKET_ERROR=WSAAsyncSelect(SkC,Handle,WM_CLIENTSOCK,FD_READ or FD_CLOSE) then
        ShowMessage('WM_SOCKET Error');
    这句话,指明了使用网络消息事件进行通信的TCP和UDP是一样的,只是一个是无连接,一个是有连接的通信而已...
      

  10.   

    请大侠mdejtod
    也给我传一份啊。狠狠的顶你一下啊!
    [email protected]