各位:
  大家好,很简单的一个SOCKET的初级问题,是这样的:
如何用TServerSocket和TClientSocket控件来两台机器的发送和接收.
写了一个简单例子,服务端程序如下:
unit U_main;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, ScktComp, winsock,Mask;type
  TForm1 = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    Button1: TButton;
    Button2: TButton;
    Panel1: TPanel;
    memo_log: TMemo;
    ServerSocket1: TServerSocket;
    edt_port: TEdit;
    Label3: TLabel;
    Memo1: TMemo;
    Button3: TButton;
    Button4: TButton;
    list_client: TListBox;
    Label4: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure ServerSocket1Listen(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket1ClientDisconnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket1ClientConnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure Button4Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    procedure write_memo(note:string);    { Private declarations }
  public
    { Public declarations }
  end;var
  Form1: TForm1;
  s:TCustomWinSocket;
implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
begin  if trim(edt_port.Text)='' then
    begin
      application.MessageBox('端口号不能为空!','提示',64);
      exit;
    end;  ServerSocket1.Port:=strtoint(edt_port.Text);
  try
    ServerSocket1.Open;
  except  end;
  button1.Enabled:=false;
  button2.Enabled:=true;
end;procedure TForm1.Button2Click(Sender: TObject);
begin
   button1.Enabled:=true;
   ServerSocket1.Close;
  write_memo('关闭监听');
  button2.Enabled:=false;
end;procedure TForm1.write_memo(note:string);
var
 t_time:string;
begin t_time:=FormatDateTime('yyyy-mm-dd hh:nn:ss',now);
 memo_log.Lines.Add(t_time+' :'+note);
end;procedure TForm1.ServerSocket1Listen(Sender: TObject;
  Socket: TCustomWinSocket);
begin
write_memo('打开监听');
end;procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  mo_note:string;
begin  mo_note:=socket.ReceiveText;
  if mo_note<>'' then
   begin
     write_memo('接收客户端信息:'+mo_note);
     //socket.SendText('0');
   end
   else begin
          write_memo('接收客户端不对!');
          //socket.SendText('-1');
        end;
end;procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  write_memo('断开客户端SOCKET连接:'+inttostr(socket.SocketHandle));
end;procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  s:=socket;
  write_memo('来自客户端的SOCKET连接IP为:'+socket.LocalAddress+'  端口号为:'+inttostr(socket.LocalPort));
  write_memo('来自客户端的SOCKET连接号:'+inttostr(socket.SocketHandle));
  list_client.Items.Add(inttostr(socket.SocketHandle));
end;procedure TForm1.Button4Click(Sender: TObject);
begin
 memo1.Lines.Clear;
end;procedure TForm1.Button3Click(Sender: TObject);
begin
      try
       s.SendText(trim(memo1.Text));
       write_memo('向客户端发送信息成功:'+trim(memo1.Text));
     except
      write_memo('向客户端发送信息失败!'+trim(memo1.Text));
     end;end;
end.客户端的程序如下:
unit Un_main;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, ScktComp;type
  Tf_main = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Button1: TButton;
    Button2: TButton;
    Panel1: TPanel;
    memo_log: TMemo;
    edt_port: TEdit;
    Memo1: TMemo;
    Button3: TButton;
    Button4: TButton;
    Label4: TLabel;
    edt_host: TEdit;
    ClientSocket1: TClientSocket;
    procedure Button1Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure ClientSocket1Connecting(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure Button2Click(Sender: TObject);
    procedure ClientSocket1Disconnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientSocket1Connect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure Button3Click(Sender: TObject);
    procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
  private
    procedure write_memo(note:string);
    { Private declarations }
  public
    { Public declarations }
  end;var
  f_main: Tf_main;implementation{$R *.dfm}procedure Tf_main.Button1Click(Sender: TObject);
begin  ClientSocket1.Address:=trim(edt_host.Text);
  ClientSocket1.Port:=strtoint(edt_port.Text);
  try
    ClientSocket1.open;
    button1.Enabled:=false;
    button2.Enabled:=true;
  except  end;end;procedure Tf_main.write_memo(note: string);
var
 t_time:string;
begin t_time:=FormatDateTime('yyyy-mm-dd hh:nn:ss',now);
 memo_log.Lines.Add(t_time+' :'+note);
end;procedure Tf_main.Button4Click(Sender: TObject);
begin
 memo1.Lines.Clear;
end;procedure Tf_main.ClientSocket1Connecting(Sender: TObject;
  Socket: TCustomWinSocket);
begin
 write_memo('正在连接服务器:'+trim(edt_host.Text));
 
end;procedure Tf_main.Button2Click(Sender: TObject);
begin
  try
    ClientSocket1.Close;
    button1.Enabled:=true;
    button2.Enabled:=false;
  except  end;
end;procedure Tf_main.ClientSocket1Disconnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  write_memo('已断开服务器:'+trim(edt_host.Text));
end;procedure Tf_main.ClientSocket1Connect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
   write_memo('已成功连上服务器:'+trim(edt_host.Text));
end;procedure Tf_main.Button3Click(Sender: TObject);
begin
  try
    ClientSocket1.Socket.SendText(trim(memo1.Text));
    write_memo('向服务端发送信息成功:'+trim(memo1.Text));
  except
    write_memo('向服务端发送信息失败!'+trim(memo1.Text));
  end;
end;procedure Tf_main.ClientSocket1Read(Sender: TObject;
  Socket: TCustomWinSocket);
var
  mo_note:string;
begin  mo_note:=socket.ReceiveText;
  if mo_note<>'' then
   begin     write_memo('接收服务端信息:'+mo_note);
     socket.SendText('0');
   end
   else begin          write_memo('接收服务端信息不对!');
          socket.SendText('-1');
        end;
end;end.运行的时候正常,可问题是我在客户端的接收过程即ClientSocket1Read过程中
可以根据接收的信息,回复服务端成功与否的标志即('0'或'-1')
如:  write_memo('接收服务端信息:'+mo_note);
     socket.SendText('0');
这样是可以的,可是我在服务端的接收过程即ServerSocket1ClientRead过程中,
却无法这样做,大家也注意到了,在这过程中
     write_memo('接收客户端信息:'+mo_note);
     //socket.SendText('0');
socket.SendText('0');这句必须要注释掉,否则运行时,客户端一向服务端发信息,
程序就会在socket.SendText('0');中产生死循环,为什么?!!!
我如何在服务端的接收过程中也能正常实现与客户端一样的应答功能呢?这样双方就能象GET一条HTTP请求一样,实现互相应答的功能.
还有在服务端的ServerSocket1ClientConnect过程中,
  write_memo('来自客户端的SOCKET连接IP为:'+socket.LocalAddress+'  端口号为:'+inttostr(socket.LocalPort));
本来我是想取得连接服务端的客户机IP的,可socket.LocalAddress取到的却是服务端的地址,怎么办?最后一个问题就是,这个例子只能实现两台机子的交互,如何实现多方交互呢(偶初学SOCKET)?
各位达人,请帮忙,万分感谢,分不是问题.

解决方案 »

  1.   

    死循环是因为:ClientSocket-》ServerSocket-》ClientSocket,所以死循环,解决的办法就是服务器收到消息后不再发消息到client端或者client端收到消息后不自动发消息到Server端;socket.RemoteHost;就是获取client的IP了。多方交互:简单点就是通过服务器程序转发,在发送的信息中包含目标地址,可以用文本,也可以自定义消息结构。
      

  2.   

    没弄过这,你查下socket的资料看看,
    网上应该比较多
      

  3.   

    TO  wuyu1981(方圆) 
      谢谢,你说的很对,而且按你说的前两个问题都已经解决.
    就是最后一个问题即
    多方交互:简单点就是通过服务器程序转发,在发送的信息中包含目标地址,可以用文本,也可以自定义消息结构。
    --------------------------------------
    如何实现?能否写个简单的例子.
    原先的服务端中有个全局变量即s:TCustomWinSocket;在接收客户端连接的过程即
    ServerSocket1ClientConnect中,通过s:=socket;将其附值,可是在多方交互时,
    这个socket只能是最新连接上服务器的客户端的socket,这样其它前面连接上服务器的客户端就
    无法与服务端通信了(可以发送信息给服务端但收不到服务端发的信息).
    跟猴子摘桃一样(只留下了最后一个).
    如何解决?希望写一个简单的例子.(最好是双方都只用文本来发送,比较好理解)
    万分感谢.
      

  4.   

    原先的服务端中有个全局变量即s:TCustomWinSocket;在接收客户端连接的过程即
    ServerSocket1ClientConnect中,通过s:=socket;将其附值,可是在多方交互时,
    这个socket只能是最新连接上服务器的客户端的socket,这样其它前面连接上服务器的客户端就
    无法与服务端通信了(可以发送信息给服务端但收不到服务端发的信息).
    跟猴子摘桃一样(只留下了最后一个).
    如何解决?
    ///////////////////////////////////////////////////////
    你的服务端不用全局变量,因为在TServerSocket中能够得到所有连接的客户端,
    ServerSocket1.Socket.ActiveConnections
    //////////为所有连接的数量
    ServerSocket1.Socket.Connections[i]
    //////////为所有的连接,每一个Connections都是一个TCustomWinSocket
      

  5.   

    多方交互:简单点就是通过服务器程序转发,在发送的信息中包含目标地址,可以用文本,也可以自定义消息结构。
    --------------------------------------
    如何实现?/////////////////////////////////////
    譬如在你的发送地方:
    ClientSocket1.Socket.SendText(trim(memo1.Text));
    -------------------->>>>>>>>>>>>>>>>
    ClientSocket1.Socket.SendText('ip:192.168.0.1,text:'+trim(memo1.Text));
    //////////指定发送到目的地:192.168.0.1,如果一台电脑上可能运行2个以上的客户端,还需把端口写入。方法一样。
    /////////////////
    在你的服务端:
    procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    var
       strDestIp:string;
       i:integer;
    .....  mo_note:=socket.ReceiveText;////////内容为ip:192.168.0.1,text:
      strDestIp:=Copy(mo_note,4,pos(',text',mo_note)-4);////得到目的地址
      for i:=0 to ServerSocket1.Socket.ActiveConnections-1 do
      begin
        if ServerSocket1.Socket.Connections[i].RemoteHost=strDestIp then/////判断服务端的所有客户端有没有IP地址为该目的地址的
        begin
            ServerSocket1.Socket.Connections[i].SendText(Copy(mo_note,pos(',text',mo_note)+6,length(mo_note)));
            break;
        end;
      end
    end;
      

  6.   

    谢谢 gzmhero(hihihi) ClientSocket1.Socket.SendText('ip:192.168.0.1,text:'+trim(memo1.Text));
    //////////指定发送到目的地:192.168.0.1,如果一台电脑上可能运行2个以上的客户端,还需把端口写入。方法一样。指定发送到目的地:192.168.0.1应该为客户端的IP吧。对了,最后一问:SOCKET中用流机制来发还是用字符数据来发?哪个好,更实用?