一台PC 对多个IP端的监控基本结构:
一台PC---> 局域网---> IP端(有300个,全是硬件:如PLC)PC :可以作为服务器端也可以为客户端
多个IP端:可作为TCPClient端、TCPServer端、UDPServer\Client端等、要求:由PC 端主动向多个IP端发送数据,由于是按一种协议的格式来发送的,多个IP端会自动有数据返回,我现在不知道究竟把PC 端作SERVER端好还是CLIENT端好?用UDP 方式好还是用TCP方式好??请大家给些可行的建议。

解决方案 »

  1.   

    请问:如果我把PC端作为TCPServer,用TCP方式来实现,不知道TCPServer端能不能向多个TCPClient端发送数据?我需要对这多个TCPClient端进行时实的数据发送,才能时实的得到返回的数据
      

  2.   

    基本结构:
    一台PC---> 局域网---> IP端(有300个,全是硬件:如PLC)上面这个结构可以看成是: 一台主控PC---> 局域网---> 多个被控PC不用管 被控端是什么硬件,因我在连接硬件时用了一个“串口转TCP/IP转换器”“串口转TCP/IP转换器”:有一个IP 地址,我只要从PC端向“串口转TCP/IP转换器”发送数据就可以啦,它会自动把IP数据包送到硬件上的.
      

  3.   

    可以的用ClientSocket(客户端)和ServerSocket(服务端)就可以。给你看个示例代码:
    unit UnitGetOnLineList;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, ScktComp;const
        ClientMax=254;  //客户端最大连接数
    type
      Client_Record=Record
         ClientHandle: Integer;           //客户端套接字句柄
         ClientSocket:TCustomWinSocket;   //客户端套接字
         ClientName:String;               //客户端计算机名称
         ClientAddress:String;            //客户端计算机IP地址
         ClientUsed: Boolean;             //客户端联机标志
      end;type
      TFrmGetOnLineList = class(TForm)
        ServerSocket1: TServerSocket;
        procedure ServerSocket1ClientConnect(Sender: TObject;
          Socket: TCustomWinSocket);
        procedure ServerSocket1ClientDisconnect(Sender: TObject;
          Socket: TCustomWinSocket);
        procedure ServerSocket1ClientError(Sender: TObject;
          Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
          var ErrorCode: Integer);
        procedure ServerSocket1ClientRead(Sender: TObject;
          Socket: TCustomWinSocket);
      private
        { Private declarations }
        Session: array[0..ClientMax] of Client_record;      //客户端连接数组
        Sessions: integer;
        procedure GetOnLineList(var ASocketIndex:integer);  //获取在线用户列表;
      public
        { Public declarations }
      end;var
      FrmGetOnLineList: TFrmGetOnLineList;implementationuses UnitDM, UnitLogin;{$R *.dfm}
    procedure TFrmGetOnLineList.GetOnLineList(var ASocketIndex:integer);
    var
      i:integer;
      SL:TStringList;
      temp:string;
    begin
      with DM1.ADOQuery1 do
      begin
        SL:=TStringList.Create;
        try
          for i := 0 to FrmLogin.lbxClientNumber.Items.Count-1 do
            begin
              temp:='';
              SQL.Clear;
              SQL.Add('Select 号码,昵称,性别,省份,头像 From RegUser ');
              SQL.Add('Where 号码='+FrmLogin.lbxClientNumber.Items.Strings[i]);          Open;
              if RecordCount<>0 then
                begin
                  temp:=Trim(FieldValues['号码'])+','+
                              Trim(FieldValues['昵称'])+','+
                              Trim(FieldValues['性别'])+','+
                              Trim(FieldValues['省份'])+','+
                              Trim(FieldValues['头像'])+','+
                              Trim(FrmLogin.lbxClientIP.Items.Strings[i]);
                  SL.Append(temp);
                end;
              Close;
            end;
          if SL.Text='' then
             Session[ASocketIndex].ClientSocket.SendText('3002')
          else
             Session[ASocketIndex].ClientSocket.SendText(SL.Text);
        finally
          SL.Free;
        end;
      end;
    end;procedure TFrmGetOnLineList.ServerSocket1ClientConnect(Sender: TObject;
      Socket: TCustomWinSocket);
    var
      i,k:integer;
    begin
      k:=-1;
      for i:=0 to Sessions do
      begin
          //在原有的客户端连接数组中有中断的客户端连接
          if not Session[i].ClientUsed then
          begin
              Session[i].ClientHandle := Socket.SocketHandle ;   //客户端套接字句柄
              Session[i].ClientSocket := Socket;                 //客户端套接字
              Session[i].ClientName := Socket.RemoteHost ;       //客户端计算机名称
              Session[i].ClientAddress := Socket.RemoteAddress ; //客户端计算机IP
              Session[i].ClientUsed := True;                     //连接数组当前位置已经占用
              Break;
          end;
          k:=i;
      end;
      if k=Sessions then
      begin
          inc(Sessions);
          Session[k].ClientHandle := Socket.SocketHandle ;
          Session[k].ClientSocket := Socket;
          Session[k].ClientName := Socket.RemoteHost ;
          Session[k].ClientAddress := Socket.RemoteAddress ;
          Session[k].ClientUsed := True;
      end;end;procedure TFrmGetOnLineList.ServerSocket1ClientDisconnect(Sender: TObject;
      Socket: TCustomWinSocket);
    var
      i:integer;
    begin
      for i:=0 to Sessions do
        begin
          if Session[i].ClientHandle =Socket.SocketHandle then
            begin
              Session[i].ClientHandle :=0;
              Session[i].ClientUsed := False;
              Break;
            end;
        end;end;procedure TFrmGetOnLineList.ServerSocket1ClientError(Sender: TObject;
      Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
      var ErrorCode: Integer);
    begin
      ErrorCode := 0;
    end;procedure TFrmGetOnLineList.ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    var
      ReceiveString:Widestring;
      SocketIndex:integer;
    begin
      //将从客户端读取的信息添加到Memo1中
      ReceiveString:=Socket.ReceiveText;
      for SocketIndex:=0 to Sessions do
        begin
          //取得匹配的客户端
          if Session[SocketIndex].ClientHandle = Socket.SocketHandle then
            GetOnLineList(SocketIndex);
        end;
    end;end.这样 这个服务端可同时处理254个客户请求。
      

  4.   

    请问上面的实现是:
       主控PC端 为TCPServer?
       被控多个IP端 为TCPClient端?我要求:由“主控PC端”主动向“被控多个IP端”发送数据,而且需要对“被控多个IP端”进行时实的数据发送.
      

  5.   

    我有些不明白,TCPServer在向 TCPClient(“被控多个IP端”)发送数据时,它是怎么指我要向哪个IP 发送数据的?
      

  6.   

    TCPServer在向 TCPClient发送数据时,TCPServer是怎么来指定某个IP的?
      

  7.   

    我在网上看到的一般是用tclientsocket做主控端,而tserversocket做受控端而且很多人都说用UDP 好,很是郁闷!!!!!
      

  8.   

    To 楼主:基本结构:
    一台PC---> 局域网---> IP端(有300个,全是硬件:如PLC)这台PC做成客户端比较合适。主要的原因是PLC这类设备一般不会主动往外送数据,而是收到指令才输出数据,在PC端与硬件设备连接成功之后,发送指令给设备。当然,PC做成服务器端也是可行的,此时,当PC端发现硬件设备与之连接之后,再发送指令给设备。PC端的程序肯定需要维护一个硬件设备的列表, 在列表中填入所有硬件设备的IP地址。程序运行之后,可以用300多个ClientSocket去同时连接这些硬件设备(一台PC可以同时创建上万个Socket,你只有300多个,没问题)。(在你的这种应用中,这台PC可以称之为"数据采集网关"。)通讯协议应该使用TCP,因为你的数据交换是要求必须可靠无误的,只有TCP才能提供可靠的数据连接。而且也只有TCP协议才能比较容易地发现连接被断开等连接故障。
      

  9.   

    请问楼上可以由服务器端主动向客户发起连接吗?------------------------------------------------
    回复人: jadeluo(秀峰) 当然,PC做成服务器端也是可行的,此时,当PC端发现硬件设备与之连接之后,再发送指令给设备。
      

  10.   

    做成双向的吧,同一个程序既可以是Server,又可以是Client,这样适用性强,但实现上会麻烦一些!
      

  11.   

    To xieyongxiang(闲人):请问楼上可以由服务器端主动向客户发起连接吗?不能。服务器端只负责侦听,并接收客户端的连接请求。
      

  12.   


    TO 回复人: jadeluo(秀峰)   不能。服务器端只负责侦听,并接收客户端的连接请求。===========================================
    如果是这样的话,我觉得用UDP 好像更合适耶~UDP 是不区分服务器端和客户端的,它只是分为发送端和接收端,发送数据时,连IP和PORT都在写在里面,那么我在PC 上写程序时应该用一个UPD控件就可以做到了,
      

  13.   

    TO 回复人: jadeluo(秀峰) 
    --------------------------------------
    记得好像你用过MOXA公司的产品(串口转TCP/IP 卡)方面的,我用的是MOXA公司的产品(NPort DE-311)串口转TCP/IP 卡,好像可以由它(如:把它设为TCPClient)主动向PC端(TCPServer)发起连接; 这样的话,我就好做了,我直接在PC端(TCPServer)向多个TCPClient端发送数据就可以啦还有,我打算用INDY:IdTCPServer控件,我看一下他的使用说明,IdTCPServer控件好像没有发送的命令,而IdTCPClient控件有发送命令:WriteBuffer;如果IdTCPServer控件有发送命令的啦,我又怎么来指写它向哪个IP发送数据呀?
    IdTCPServer控件的ReadBuffer接收命令好像也不能得到是哪个IP客户端来的数据,我需要知道是哪个客户端IP,以便做其它操作。
      

  14.   

    To 楼主:"...... 我用的是MOXA公司的产品(NPort DE-311)串口转TCP/IP 卡,好像可以由它(如:把它设为TCPClient)主动向PC端(TCPServer)发起连接; 这样的话,我就好做了,我直接在PC端(TCPServer)向多个TCPClient端发送数据就可以啦 ......"其实,你PC端做成服务器端还是客户端,编程量是一样的,并不会有什么太大的区别。区别:
                   
    1. PC端做成服务器端,只要建立一个ServerSocket实例,转换器请求连接时,由ServerSocket实例自动创建一个Socket与之相连,而这个客户端是哪一个,则需要通过查找PC端预配置好的IP地址清单才能知道。2. PC端做成客户端,需要按照PC端预配置好的IP地址清单,建立若干个Socket与转换器连接。个人认为,应该是PC端做成客户端更容易一些。另外,建议使用TClientSocket或者TServerSocket,而不要使用IdTCPClient或者IdTCPServer。
      

  15.   

    TO 回复人: jadeluo(秀峰) 个人认为,应该是PC端做成客户端更容易一些。另外,建议使用TClientSocket或者TServerSocket,而不要使用IdTCPClient或者IdTCPServer。
    ------------------------------------------------   谢谢你的答复,按照你说的,在PC端作为TClientSocket,我将生成300个TClientSocket实例或用300个控件,分别对300个不同IP端(TServerSocket)进行数据发送,那么我觉得应该用一个线程,专门用来发送,   由于我每次发送都有数据自动返回,固还要建立一个线程用来接收数据,这样应该比较好吧?
      

  16.   

    To 楼主:如果TClientSocket工作在阻塞方式下的话, 你需要使用线程来接收数据。如果TClientSocket工作在非阻塞方式下的话, 你可以在TClientSocket的OnRead事件中接收数据,而不需要使用线程。另外,千万别使用300个控件的这种方式哦。 :)