Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Varios
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #21  
Antiguo 11-04-2017
Avatar de hgiacobone
hgiacobone hgiacobone is offline
Miembro
 
Registrado: may 2003
Ubicación: La Plata, Bs. As., Argentina
Posts: 165
Poder: 21
hgiacobone Va por buen camino
Cita:
Empezado por escafandra Ver Mensaje
...Cuando tienes varias instancias de un ejecutable, cada una con ventanas, los Handles no son los mismos...
Ah, ok.... o sea, Windows tomará un ID diferente aunque sea el mismo EXE?

Cita:
Empezado por escafandra Ver Mensaje
...Si el protocolo es UDP no hace falta conexión previa u puedes enviar un datagrama UDP a la IP Broadcast con lo que todas las instancias de MyApp, lo recibirán...
Entiendo, pero lo planteado en este foro hizo que dudara por el uso del port.
¿Entoneces es posible utilizar UDP aunque haya varias instancias RDP ?
__________________
Gracias de antemano por vuestra ayuda.
·.:*:.·Yako·.:*:.·
Responder Con Cita
  #22  
Antiguo 12-04-2017
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.195
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Es posible tener varios servidores escuchando en la misma máquina por el mismo puerto, no es una situación común pero no es un imposible. Para esto está el Multicast.

Te pongo un ejemplo de servidor socket multicast en un thread para poder compaginarlo con una app de ventanas:
Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, WinSock;

type
  TServer = class(TThread)
  private
  protected
    procedure Execute; override;
  public
  end;


  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    Server: TServer;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}



//---------------------------------------------------------------------------
// Establecer y ejecutar Timeout en winsock recv / recvfrom
// retorna como winSock.Select
//  -1: si error
//   0: fuera de tiempo
// > 0: Datos listos para leer
function TimeoutSocket(Sock: WinSock.TSOCKET; TimeOut: integer): integer;
var
  FDSet: WinSock.TFDSET;
  TimeVal: WinSock.TTIMEVAL;
begin
  TimeVal.tv_sec:= TimeOut div 1000;
  TimeVal.tv_usec:= TimeOut mod 1000;
  FD_ZERO(FDSet);
  FD_SET(Sock, FDSet);
  Result:= WinSock.Select(0, @FDSet, nil, nil, @TimeVal)
end;


procedure TServer.Execute;
const
  BufferSize = 1024;
  Port = 9090;
var
  WSA: WinSock.TWSADATA;
  Sock: WinSock.TSOCKET;
  Addr: WinSock.sockaddr_in;
  Buffer: array[0..BufferSize-1] of AnsiChar;
  Len, AddrSize: integer;
  dwTime: DWORD;
  ValMulticast: AnsiCHAR;
begin
  if (WinSock.WSAStartup(MakeWord(2, 2), WSA) <> 0) then exit;
  Sock := WinSock.socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
  if (Sock <> INVALID_SOCKET) then
  begin
    dwTime:= 1000;
    ValMulticast:= #1;
    setsockopt(Sock, SOL_SOCKET, SO_RCVTIMEO, PCHAR(@dwTime), sizeof(dwTime));
    setsockopt(Sock, SOL_SOCKET, SO_REUSEADDR, @ValMulticast, sizeof(ValMulticast));
    setsockopt(Sock, IPPROTO_IP, IP_MULTICAST_LOOP, 0, 1);
    Addr.sin_family := AF_INET;
    Addr.sin_addr.s_addr := INADDR_ANY;
    Addr.sin_port := WinSock.htons(Port);
    AddrSize := sizeof(Addr);

    // Asociamos el socket al puerto y a escuchar
    if (bind(Sock, Addr, AddrSize) <> -1) then
    begin
      // Bucle de escucha...
      while not Terminated do
      begin
        Len := 0;

        // Comprobamos si ha recibido algun mensaje que leer
        if TimeoutSocket(Sock, 500) > 0 then
        begin
          ZeroMemory(@Buffer[0], BufferSize);
          Len := WinSock.recvfrom(Sock, Buffer, BufferSize-1, 0, Addr, AddrSize);
          // Leemos el paquete enviado
          if (Len > 0) and (Len < BufferSize) then
          begin
            Windows.Beep(1000, 100);
            MessageBox(0, Buffer, 'Eureka',0);
          end;
        end;
      end;
    end;
    WinSock.closesocket(Sock);
  end;
  WinSock.WSACleanUp;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Server:= TServer.Create(false);
end;

end.

Este servidor se pone a la escucha en el puerto 9090 y podemos tener varios en ejecución.

Ahora el cliente debe enviar mensajes UDP al Broadcast por el puerto 9090, para ello debemos calcular esa dirección. Te pongo un ejemplo de cliente que envía un mensaje a todos los servidores a la vez, estén o no en la misma máquina:
Código Delphi [-]
unit Unit2;

interface

uses
  Windows, WinSock, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm2 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

TMIB_IPADDRROW = packed record
  dwAddr: DWORD;
  dwIndex: DWORD;
  dwMask: DWORD;
  dwBCastAddr: DWORD;
  dwReasmSize: DWORD;
  unused1: SmallInt;
  wType: SmallInt;
end;

TMIB_IPADDRTABLE = record
  dwNumEntries: DWORD;
  table: array[0..0] of TMIB_IPADDRROW;
end;
PMIB_IPADDRTABLE = ^TMIB_IPADDRTABLE;


function GetIpAddrTable(IpAddrTable: PMIB_IPADDRTABLE; pdwSize: PULONG;
  Order: BOOL): DWORD; stdcall; external 'iphlpapi.dll' name 'GetIpAddrTable';

var
  Form2: TForm2;

implementation

{$R *.dfm}
function GetCurrentIP: DWORD;
var
  Wsa: WSADATA;
  Name: array[0..255] of char;
  hostinfo: PHOSTENT;
begin
  Result:= 0;
  FillChar(Wsa, SizeOf(WSAData), 0);
  if WSAStartup(MAKEWORD(2, 2), Wsa) = 0 then
  begin
    if gethostname(Name, SizeOf(Name)) = 0 then
    begin
      hostinfo:= gethostbyname(Name);
      if hostinfo <> nil then
        Result:= PDWORD(hostinfo^.h_addr_list^)^;
    WSACleanup;
    end;
  end;
end; 
 
function GetBrodcastAddress: String;
var
  pIPAddrTable: PMIB_IPADDRTABLE;
  dwSize: DWORD;
  i: integer;
  BroadCastInAddr: IN_ADDR;
begin
  BroadCastInAddr.S_addr:= 0;
  dwSize:= 0;
  GetIpAddrTable(nil, @dwSize, true);
  GetMem(pIPAddrTable, dwSize);
  if pIPAddrTable<>nil then
  begin
    if GetIpAddrTable(pIPAddrTable, @dwSize, true) = NO_ERROR then
      for i:=0 to  pIPAddrTable^.dwNumEntries-1 do
      begin
        if GetCurrentIP = pIPAddrTable^.table[i].dwAddr then
        begin
          BroadCastInAddr.S_addr:= pIPAddrTable^.table[i].dwAddr or not pIPAddrTable^.table[i].dwMask;
          break;
        end;
      end;
    FreeMem(pIPAddrTable);
  end;
  Result:= inet_ntoa(BroadCastInAddr);
end;

procedure SendUDP(Msg: AnsiString; IP: String; Port: WORD);
var
 Wsa: WSADATA;
 S: TSocket;
 Addr: WinSock.sockaddr_in;
 Host: PHostent;
 IPAddr: ^integer;
begin
  if WSAStartup(MAKEWORD(2, 2), Wsa) = 0 then
  try
    S:= Socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if S <> INVALID_SOCKET then
    begin
      Host:= gethostbyname(PAnsiCHAR(IP));
      IPAddr:= @Host.h_addr_list^[0];
      Addr.sin_family:= AF_INET;
      Addr.sin_addr.S_addr:= IPAddr^;
      Addr.sin_port:= htons(Port);
      Sendto(S, PAnsiChar(Msg)^, Length(Msg), 0, Addr, SizeOf(sockaddr_in));
     end;
  finally
    WSACleanup();
  end;
end;

procedure TForm2.Button1Click(Sender: TObject);
begin
  SendUDP('Hola', GetBrodcastAddress, 9090);
end;

end.

Probado en Win10 y compilado con Delphi 7


Espero que resuelva tu duda y en general la duda que originó ente hilo.


Saludos.
Responder Con Cita
  #23  
Antiguo 13-04-2017
Avatar de hgiacobone
hgiacobone hgiacobone is offline
Miembro
 
Registrado: may 2003
Ubicación: La Plata, Bs. As., Argentina
Posts: 165
Poder: 21
hgiacobone Va por buen camino
Muchas, pero muchas, gracias a migo escafandra... pero esto es muy elevado para mi entendimiento

Primero, porque creo yo tengo un error de concepto:
-En este caso, existe un pequeño ejecutable que monitorea un proceso. Llamemos a este "2do.exe"
-Luego está la aplicacion principal, que cada usurario levanta mediante una conexion RDP (Windows). Llamemos "1ro.exe". O sea, hay varios "1ro.exe" y un solo "2do.exe"

Entonces, el programa monitor (2do.exe) cada vez que realiza una operación, debería enviar a modo de mensaje de texto, ese resultado a cada instancia del programa (1ro.exe) y este, cuando lo reciba, lo mostrará en pantalla o como se prefiera. Yo pensaba que el monitor debería ser el Servidor y las otras aplicaciones los clientes, pero parece que es a la inversa, no?

Segundo, observo que utilizas la unidad WinSock. ¿Es una unidad estandar de Delphi o solo si adquieres el paquete Indy de las versiones Archictect/Professional?

Tercero: he instalado por sugerencia de varios, unos componentes "free" denominados Overbyte ICS que tienen infinidad de componentes de conexion TCP/UDP entre ellos:
> OverbyteIcsWSocket.pas Winsock component - TCP, UDP, DNS,...
> OverbyteIcsWSocketE.pas Register procedure and property editor for TWSocket
> OverbyteIcsWSocketS.pas Winsock component for building servers
> OverbyteIcsWSocketTS.pas Winsock component for building multithreaded servers
> OverbyteIcsDnsQuery DNS lookup component - useful for getting MX records

...que aun no se ni cómo utilizarlos.
¿Supones que podría reemplazar los WinSocks por ellos o no es conveniente?
__________________
Gracias de antemano por vuestra ayuda.
·.:*:.·Yako·.:*:.·
Responder Con Cita
  #24  
Antiguo 13-04-2017
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.195
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Cita:
Empezado por hgiacobone Ver Mensaje
Entonces, el programa monitor (2do.exe) cada vez que realiza una operación, debería enviar a modo de mensaje de texto, ese resultado a cada instancia del programa (1ro.exe) y este, cuando lo reciba, lo mostrará en pantalla o como se prefiera. Yo pensaba que el monitor debería ser el Servidor y las otras aplicaciones los clientes, pero parece que es a la inversa, no?
En principio sujerí que monitor fuese el servidor para simplificar la conexión pero eso requiere que los clientes pregunten al servidor cada cierto tiempo alejándose de la idea de que sea el Monitor el que envíe mensajes cuando le plazca a las instancias del 1r0.exe que deben estar a la escucha. Esto requiere que Monitor actúe como cliente y el resto como servidores a la escucha por el mismo puerto. Esta idea es la que, en principio, va en contra de la teoría que dice que "solo puede haber un servidor escuchando en un mismo puerto", que es cierta salvo alguna excepción como la que muestro.

Cita:
Empezado por hgiacobone Ver Mensaje
Segundo, observo que utilizas la unidad WinSock. ¿Es una unidad estandar de Delphi o solo si adquieres el paquete Indy de las versiones Archictect/Professional?
La API WinSock es una unidad estándar de windows. Los Sockets son la vía a bajo nivel que el S.O. nos brinda para manejar los paquetes en la red permitiéndonos enlazar la capa de aplicación con la de transporte. Son un estándar básico adoptado pos casi todos los S.O. por lo que te sirve para conectar con cualquier máquina en la red. Como es natural, Delphi y otros lenguajes, son capaces de manejar esa API. Los componentes de terceros para comunicación por red, usan winsock, como no podía ser de otra manera, para realizar sus propósitos.

Cita:
Empezado por hgiacobone Ver Mensaje
Tercero: he instalado por sugerencia de varios, unos componentes "free" denominados Overbyte ICS que tienen infinidad de componentes de conexion TCP/UDP entre ellos:
> OverbyteIcsWSocket.pas Winsock component - TCP, UDP, DNS,...
> OverbyteIcsWSocketE.pas Register procedure and property editor for TWSocket
> OverbyteIcsWSocketS.pas Winsock component for building servers
> OverbyteIcsWSocketTS.pas Winsock component for building multithreaded servers
> OverbyteIcsDnsQuery DNS lookup component - useful for getting MX records

...que aun no se ni cómo utilizarlos.
¿Supones que podría reemplazar los WinSocks por ellos o no es conveniente?
Como ya te digo, esos componentes no reemplazan, sino que usan internamente winsock. Para el uso concreto que se pide en este hilo, considero que la mejor forma (por poco usual) es trabajar a bajo nivel con sockets (winsock) para tener el control absoluto de lo que hacen y como se configuran (setsockopt)

Ignoro como quieres que 1ro.exe trabaje con los mensajes recibidos, por eso en el ejemplo puse un MessageBox. Ten en cuenta que todo el código servidor está en un Thread, lo que significa que no puedes usar a las bravas la VCL desde él. Para sincronizar el hilo con el formulario debes usar el método Synchronize o mejor aún en este caso, mensajes Windows desde el hilo a la ventana del formulario que elijas, para ello basta con que al crear el hilo le pases el Handle de dicha ventana y uses SendMessage desde el hilo, cuando recibas un mensaje UDP (que viene de Monitor.exe). En tu formulario generas una función de tratamiento de esos mensajes personalizados y funcionará como un evento.

Saludos.

Última edición por escafandra fecha: 13-04-2017 a las 18:33:59.
Responder Con Cita
  #25  
Antiguo 13-04-2017
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.195
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
A modo de ilustración, te muestro el servidor modificado para disparar un evento al recibir un mensaje desde el cliente. En este caso, el formulario incorpora un TLabel donse se escribirá el mensaje de texto recibido. Uso un mensaje de Windows pero también podrías modificarlo para usar Synchronize.

Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, WinSock, StdCtrls;

const
  WM_MSG = WM_USER + 1;

type
  TServer = class(TThread)
  private
    FWND: HWND;
  protected
    procedure Execute; override;
  public
    constructor Create(const WND: HWND);
  end;


  TForm1 = class(TForm)
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
  private
    Server: TServer;
    procedure OnMsg(var Msg: TMessage); message WM_MSG;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
constructor TServer.Create(const WND: HWND);
begin
  FWND:= WND;
  inherited Create(false);
end;

procedure TServer.Execute;
const
  BufferSize = 1024;
  Port = 9090;
var
  WSA: WinSock.TWSADATA;
  Sock: WinSock.TSOCKET;
  Addr: WinSock.sockaddr_in;
  Buffer: array[0..BufferSize-1] of AnsiChar;
  Len, AddrSize: integer;
  dwTime: DWORD;
  ValMulticast: AnsiCHAR;
begin
  if (WinSock.WSAStartup(MakeWord(2, 2), WSA) <> 0) then exit;
  Sock := WinSock.socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
  if (Sock <> INVALID_SOCKET) then
  begin
    dwTime:= 1000;
    ValMulticast:= #1;
    // Establecemos un timeout de bloqueo
    WinSock.setsockopt(Sock, SOL_SOCKET, SO_RCVTIMEO, PAnsiCHAR(@dwTime), sizeof(dwTime));
    // Permitimos vincular el puerto más veces
    WinSock.setsockopt(Sock, SOL_SOCKET, SO_REUSEADDR, @ValMulticast, sizeof(ValMulticast));
    // Establecemos la opción multicast(Activa por defecto)
    WinSock.setsockopt(Sock, IPPROTO_IP, IP_MULTICAST_LOOP, nil, 1);
    Addr.sin_family := AF_INET;
    Addr.sin_addr.s_addr := INADDR_ANY;
    Addr.sin_port := WinSock.htons(Port);
    AddrSize := sizeof(Addr);

    // Asociamos el socket al puerto y a escuchar
    if (bind(Sock, Addr, AddrSize) <> -1) then
    begin
      // Bucle de escucha...
      while not Terminated do
      begin
        ZeroMemory(@Buffer[0], BufferSize);
        Len := WinSock.recvfrom(Sock, Buffer, BufferSize-1, 0, Addr, AddrSize);
        // Leemos el paquete enviado
        if (Len > 0) and (Len < BufferSize) then
        begin
          Windows.Beep(1000, 100);
          // Se lo comunicamos al formulario
          Windows.SendMessage(FWND, WM_MSG, WPARAM(@Buffer[0]), 0);
        end;
      end;
    end;
    WinSock.closesocket(Sock);
  end;
  WinSock.WSACleanUp;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Server:= TServer.Create(Handle);
end;

// Respondiendo al mensaje recibido por el Thread servidor
procedure TForm1.OnMsg(var Msg: TMessage);
begin
  Label1.Caption:= PAnsiChar(Msg.WParam);
end;

end.


Saludos

Última edición por escafandra fecha: 13-04-2017 a las 18:52:02.
Responder Con Cita
  #26  
Antiguo 13-04-2017
Avatar de hgiacobone
hgiacobone hgiacobone is offline
Miembro
 
Registrado: may 2003
Ubicación: La Plata, Bs. As., Argentina
Posts: 165
Poder: 21
hgiacobone Va por buen camino
Cita:
Empezado por escafandra Ver Mensaje
A modo de ilustración, te muestro el servidor modificado para disparar un evento al recibir un mensaje desde el cliente. En este caso, el formulario incorpora un TLabel donse se escribirá el mensaje de texto recibido. Uso un mensaje de Windows pero también podrías modificarlo para usar Synchronize. Saludos
Muchas gracias nuevamente.
Ya generé ambos ejemplos, el cliente y el server, pero no pasa nada...
Inicio primero el Server y luego el cliente, hago clic en el Button1 y nada....
Inicio primero el Cliente y luego el Server, hago clic en el Button1 y nada....
Mi LAN es 192.168.14.xxx y la funcion GetBrodcastAddress; está devolviendo correctamente 192.168.14.255
Probé otros Port y nada...
que puede ser ?
__________________
Gracias de antemano por vuestra ayuda.
·.:*:.·Yako·.:*:.·
Responder Con Cita
  #27  
Antiguo 13-04-2017
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.195
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Posiblemente dependa de la versión del delphi que uses.
La versión Cliente que he probado con delphi7 y Berlin es esta:
Código Delphi [-]
unit Unit2;

interface

uses
  Windows, WinSock, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm2 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

TMIB_IPADDRROW = packed record
  dwAddr: DWORD;
  dwIndex: DWORD;
  dwMask: DWORD;
  dwBCastAddr: DWORD;
  dwReasmSize: DWORD;
  unused1: SmallInt;
  wType: SmallInt;
end;

TMIB_IPADDRTABLE = record
  dwNumEntries: DWORD;
  table: array[0..0] of TMIB_IPADDRROW;
end;
PMIB_IPADDRTABLE = ^TMIB_IPADDRTABLE;


function GetIpAddrTable(IpAddrTable: PMIB_IPADDRTABLE; pdwSize: PULONG;
  Order: BOOL): DWORD; stdcall; external 'iphlpapi.dll' name 'GetIpAddrTable';

var
  Form2: TForm2;

implementation

{$R *.dfm}
function GetCurrentIP: DWORD;
var
  Wsa: WSADATA;
  Name: array[0..255] of AnsiChar;
  hostinfo: PHOSTENT;
begin
  Result:= 0;
  FillChar(Wsa, SizeOf(WSAData), 0);
  if WSAStartup(MAKEWORD(2, 2), Wsa) = 0 then
  begin
    if gethostname(Name, SizeOf(Name)) = 0 then
    begin
      hostinfo:= gethostbyname(Name);
      if hostinfo <> nil then
        Result:= PDWORD(hostinfo^.h_addr_list^)^;
    WSACleanup;
    end;
  end;
end; 
 
function GetBrodcastAddress: AnsiString;
var
  pIPAddrTable: PMIB_IPADDRTABLE;
  dwSize: DWORD;
  i: integer;
  BroadCastInAddr: IN_ADDR;
begin
  BroadCastInAddr.S_addr:= 0;
  dwSize:= 0;
  GetIpAddrTable(nil, @dwSize, true);
  GetMem(pIPAddrTable, dwSize);
  if pIPAddrTable<>nil then
  begin
    if GetIpAddrTable(pIPAddrTable, @dwSize, true) = NO_ERROR then
      for i:=0 to  pIPAddrTable^.dwNumEntries-1 do
      begin
        if GetCurrentIP = pIPAddrTable^.table[i].dwAddr then
        begin
          BroadCastInAddr.S_addr:= pIPAddrTable^.table[i].dwAddr or not pIPAddrTable^.table[i].dwMask;
          break;
        end;
      end;
    FreeMem(pIPAddrTable);
  end;
  Result:= inet_ntoa(BroadCastInAddr);
end;

procedure SendUDP(Msg: AnsiString; IP: AnsiString; Port: WORD);
var
 Wsa: WSADATA;
 S: TSocket;
 Addr: WinSock.sockaddr_in;
 Host: PHostent;
begin
  if WinSock.WSAStartup(MAKEWORD(2, 2), Wsa) = 0 then
  try
    S:= Socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if S <> INVALID_SOCKET then
    begin
      Host:= WinSock.gethostbyname(PAnsiCHAR(IP));
      Addr.sin_family:= AF_INET;
      Addr.sin_addr.S_addr:= PInAddr(Host.h_addr_list^)^.S_addr;
      Addr.sin_port:= WinSock.htons(Port);
      WinSock.Sendto(S, PAnsiChar(Msg)^, Length(Msg), 0, Addr, SizeOf(sockaddr_in));
     end;
  finally
    WinSock.WSACleanup();
  end;
end;

procedure TForm2.Button1Click(Sender: TObject);
begin
  SendUDP('Hola', GetBrodcastAddress, 9090);
end;

end.


Ten en cuenta que el UNICODE juega malas pasadas. Subo un proyecto con fuentes y ejecutables compilados.
Archivos Adjuntos
Tipo de Archivo: rar Multiserver_scr.rar (4,8 KB, 9 visitas)
Tipo de Archivo: rar Multiserver_Server.rar (156,2 KB, 4 visitas)
Tipo de Archivo: rar Multiserver_Client.rar (155,1 KB, 6 visitas)

Última edición por escafandra fecha: 13-04-2017 a las 20:13:11.
Responder Con Cita
  #28  
Antiguo 17-04-2017
jars jars is offline
Miembro
 
Registrado: mar 2004
Posts: 279
Poder: 21
jars Va por buen camino
Excelente aporte Escafandra!!!
Responder Con Cita
  #29  
Antiguo 17-04-2017
jars jars is offline
Miembro
 
Registrado: mar 2004
Posts: 279
Poder: 21
jars Va por buen camino
Escafandra, te hago el siguiente planteo que difiere del expuesto hasta ahora.
Yo tengo actualmente un programa que actúa como servidor usando TServerSocket en modo nonblocking que envía cada 2 segundos registros con el método SendBuf a cada uno de los clientes (TClientSocket) que se hayan conectado. El tamaño de cada paquete comprimido puede ser algo mas de 8k. Como suelen ser varias pc's clientes, esto genera bastante trabajo del lado servidor que ademas tiene que ir recolectando y haciendo muchos calculos, luego volcar la información a sus respectivos registros, comprimirlos y luego enviar a cada cliente. Si esto quisiera hacerlo con UDP, como debería ser ya que de este modo haría un solo envío?
Gracias.
Responder Con Cita
  #30  
Antiguo 17-04-2017
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.195
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Cita:
Empezado por jars Ver Mensaje
Escafandra, te hago el siguiente planteo que difiere del expuesto hasta ahora.
Yo tengo actualmente un programa que actúa como servidor usando TServerSocket en modo nonblocking que envía cada 2 segundos registros con el método SendBuf a cada uno de los clientes (TClientSocket) que se hayan conectado. El tamaño de cada paquete comprimido puede ser algo mas de 8k. Como suelen ser varias pc's clientes, esto genera bastante trabajo del lado servidor que ademas tiene que ir recolectando y haciendo muchos calculos, luego volcar la información a sus respectivos registros, comprimirlos y luego enviar a cada cliente. Si esto quisiera hacerlo con UDP, como debería ser ya que de este modo haría un solo envío?
Gracias.
1. Por lo que entiendo solo debes realizar los cálculos cada vez que vas a enviar y luego recorrer los clientes para enviarles exactamente lo mismo.

2. Si quieres hacer un solo envío de un paquete vía Broadcast, debes hacerlo como en el ejemplo que público. Un sólo envio a la dirección Broadcast previamente calculada desde el servidor. El ejemplo permite varios servidores y varios clientes sin cambiar el código, pero si quieres que los servidores envíen puedes establecer un bucle de comunicación o simplemente implementar el procedimiento SendUDP en cada uno. Esto requiere que cada cliente tenga un rhread a la 3scucha, es decir, también son servidores. Si las maquinas van a ser distintas no es preciso usar SO_REUSEADDR. Ten en cuenta que todas las app pueden ser clientes y servidores a un tiempo si quieres y que en UDP no precisas una conexión previa lo que es bueno por una parte pero no asegura que el paquete sea recibido.


Saludos
Responder Con Cita
  #31  
Antiguo 17-04-2017
jars jars is offline
Miembro
 
Registrado: mar 2004
Posts: 279
Poder: 21
jars Va por buen camino
Y como se puede lidiar con paquetes que no llegan o cuando se fragmenta en mas de uno?
Responder Con Cita
  #32  
Antiguo 17-04-2017
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.195
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Cita:
Empezado por jars Ver Mensaje
Y como se puede lidiar con paquetes que no llegan o cuando se fragmenta en mas de uno?
Queda de mano del desarrollador. Realiza un checksum al enviar y al recibir y sabrás si el envío es correcto. En caso contrario habrà que pedir al servidor que lo repita, por ejemplo. La ventaja de TCP es que el protocolo asegura el envío.

Saludos.
Responder Con Cita
  #33  
Antiguo 17-04-2017
jars jars is offline
Miembro
 
Registrado: mar 2004
Posts: 279
Poder: 21
jars Va por buen camino
Ok, entonces veo que es preferible seguir como hasta ahora con TCP.
Responder Con Cita
  #34  
Antiguo 21-04-2017
jars jars is offline
Miembro
 
Registrado: mar 2004
Posts: 279
Poder: 21
jars Va por buen camino
Como sería esto mismo pero que el servidor envíe mensajes udp a clientes en distintas pc´s?
Responder Con Cita
  #35  
Antiguo 21-04-2017
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.195
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
El esquema del ejemplo funciona con cualquier máquina en la Red con el mismo código. Un cliente que envía mensajes a servidores en red a través de la dirección BroadCast.


Saludos.
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Dos instancias de SQL Server parecen ser la misma Faust MS SQL Server 2 22-10-2011 00:13:07
¿Cómo usar mutex e impedir dos instancias de la misma app? Blaster OOP 1 11-08-2008 05:05:29
Cuantas instancias de nuestro exe están corriendo seoane Trucos 3 06-03-2007 02:58:41
Compartir "objetos" entre varias instancias mafebresv Varios 4 17-01-2006 00:38:23
Como evitar 2 instancias de una misma ventana hija edgusano .NET 5 12-12-2005 17:40:40


La franja horaria es GMT +2. Ahora son las 22:29:55.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi