Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   C++ Builder (https://www.clubdelphi.com/foros/forumdisplay.php?f=13)
-   -   ¿procesos que charlan entre ellos usando tuberias con nombre? (https://www.clubdelphi.com/foros/showthread.php?t=86756)

aguml 05-10-2014 16:54:13

Amigo he estado haciendo pruebas con la api que comentas pero claro, tu usas un tipo SOCKET y yo intento hacer lo mismo con un TSocketServer y un TSocketClient y la verdad es que todo lo que pruebo acaba retornandome false en TransmitFile. He probado esto:

Código PHP:

bool transmitido;
if(
IsServer){
   
transmitido TransmitFile((unsigned int)ServerSocket->Socket->Connections[0]->Handle, (HANDLE)hFiletamanio0,0,0,0);
}else{
   
transmitido TransmitFile((unsigned int)ClientSocket->Socket->Handle, (HANDLE)hFiletamanio0,0,0,0);


y esto:
Código PHP:

bool transmitido;
if(
IsServer){
   
transmitido =  TransmitFile((unsigned  int)ServerSocket->Socket->Handle,  (HANDLE)hFiletamanio0,0,0,0);
}else{
   
transmitido TransmitFile((unsigned int)ClientSocket->Socket->Handle, (HANDLE)hFiletamanio0,0,0,0);


y tambien esto:
Código PHP:

bool transmitido;
if(
IsServer){
   
transmitido =  TransmitFile((unsigned  int)ServerSocket->Handle,  (HANDLE)hFiletamanio0,0,0,0);
}else{
   
transmitido TransmitFile((unsigned int)ClientSocket->Handle, (HANDLE)hFiletamanio0,0,0,0);


y en todos los casos retorna como false y en el receptor no hay señales de que se reciba algo. Son asincronicos y no se si esto tiene que ver.

escafandra 06-10-2014 00:08:12

Para poder usar la API de winsocket desde los componentes VCL TServerSocket y TClientSocket, debes usar ServerSocket->Socket->SocketHandle o ClientSocket->Socket->SocketHandle


Saludos.

aguml 06-10-2014 16:47:30

1 Archivos Adjunto(s)
Bueno amigo, he estado viendo el modo en que me indicabas y he modificado mi funcion para que use lo que me indicabas, o sea, uso TransmitFile y una funcion propia llamada ReceiveFile. El problema es que el archivo que recibo es corrupto porque termina la funcion de recepcion pero no recibo todos los bytes. He comprobado que en la funcion ReceiveFile salgo del bucle con el break en vez de salir porque nBytes sea igual a FileSize. Lo que pienso es que se pueden estar perdiendo bytes por el camino pero no tengo ni idea ya que uso TransmitFile y no se como funciona esta por dentro. Adjunto el proyecto por si quereis mirarlo a ver que puede estar pasando.

escafandra 07-10-2014 22:12:38

Tienes un eror de concepto. Cuando esperas recibir el archivo y se dispara el evento SocketRead, en tu código, primero lees cosas (estructura del archivo, MD5...) con lo que estás perdiendo datos, pues en ese momento ya estás recibiendo los primeros bloques del archivo. Fíjate en este cambio que realizo en tu código y verás que ya funciona. Seguramente este error lo tenías en otras formas de leer tu archivo:

Código PHP:

void __fastcall TChatForm::SocketRead(TCustomWinSocket *Socket)
{
  if(
recvFile == true && recvStructFile == true)
  {
           
//Aqui recibimos el archivo
           
int recibidos ReceiveFile(Socket->SocketHandleNewPath.c_str(), archivo.size);

           
RichEdit1->SelStart RichEdit1->Text.Length();
           
RichEdit1->SelLength 0;
           
RichEdit1->SelAttributes->Color clPurple;
           
RichEdit1->Lines->Add("Finalizó la recepcion del archivo.");

           
recvFile false;
           
recvStructFile false;
           
archivo.end true;
           if(
recibidos != archivo.size)
           {
                
RichEdit1->SelStart RichEdit1->Text.Length();
                
RichEdit1->SelLength 0;
                
RichEdit1->SelAttributes->Color clPurple;
                
RichEdit1->Lines->Add("El archivo está corrupto. El tamaño del archivo enviado y del recibido son diferentes.");
           }else{
                
RichEdit1->SelStart RichEdit1->Text.Length();
                
RichEdit1->SelLength 0;
                
RichEdit1->SelAttributes->Color clPurple;
                
RichEdit1->Lines->Add("Archivo recibido correctamente.");
           }
           
Edit1->Enabled true;
           
ButtonSendFile->Enabled true;
           
TrackBarMiliseconds->Enabled true;
           
CheckBoxListen->Enabled true;
           
ButtonExit->Enabled true;
           
ButtonDisconnect->Enabled true;

           
//Calculo el MD5 del archivo recibido y lo comparo con el del archivo enviado
           
char md5[33];

           
memset(md50sizeof(md5));
           
strcpy(md5ObtenerMD5(NewPath.c_str()).c_str());
           
           if(
strncmp(md5archivo.MD532) == 0)
           {
                
RichEdit1->SelStart RichEdit1->Text.Length();
                
RichEdit1->SelLength 0;
                
RichEdit1->SelAttributes->Color clPurple;
                
RichEdit1->Lines->Add(AnsiString().sprintf("Los MD5 coinciden. MD5: %s"md5));
           }else{
                
RichEdit1->SelStart RichEdit1->Text.Length();
                
RichEdit1->SelLength 0;
                
RichEdit1->SelAttributes->Color clRed;
                
RichEdit1->Lines->Add(AnsiString().sprintf("Los MD5 no coinciden. MD5 del enviado: %s | MD5 del recibido: %s"archivo.MD5md5));
           }

           
SetForegroundWindow(ChatForm->Handle);
  }


  
// Cuando el servidor envia datos al ciente y este los ha de procesar
  
char flagFile[SIZEFLAG] = {"\n\n_File_\n\n\0"};
  
unsigned char *buffer;
  
int size,lenBuff;
  
lenBuff Socket->ReceiveLength();
  
buffer = new unsigned char[lenBuff];
  
memset(buffer,0,sizeof(buffer));

  
size Socket->ReceiveBuf(buffer,lenBuff);
  if(
strcmp(bufferflagFile) == 0)
  {
        
recvFile true;
        
RichEdit1->SelStart RichEdit1->Text.Length();
        
RichEdit1->SelLength 0;
        
RichEdit1->SelAttributes->Color clPurple;
        
RichEdit1->Lines->Add("Recibiendo archivo. Espera a que termine y no cierres la aplicación.");
        
Edit1->Enabled false;
        
ButtonSendFile->Enabled false;
        
TrackBarMiliseconds->Enabled false;
        
CheckBoxListen->Enabled false;
        
ButtonExit->Enabled false;
        
ButtonDisconnect->Enabled false;
  }
  else if(
recvFile == true && size == sizeof(archivo) )
  {
        
memcpy(archivo.namebuffersizeof(archivo.name));
        
memcpy(&archivo.sizebuffer sizeof(archivo.name), sizeof(archivo.size));
        
memcpy(&archivo.blocksbuffer sizeof(archivo.name) + sizeof(archivo.size), sizeof(archivo.blocks));
        
memcpy(&archivo.endbuffer sizeof(archivo.name) + sizeof(archivo.size) + sizeof(archivo.blocks), sizeof(archivo.end));
        
memcpy(&archivo.MD5buffer sizeof(archivo.name) + sizeof(archivo.size) + sizeof(archivo.blocks) + sizeof(archivo.end), sizeof(archivo.MD5));

        if(
archivo.end == false)
        {
           
NewPath ExtractFilePath(Application->ExeName) +"_"archivo.name;

           if(
FileExists(NewPath))
                
DeleteFile(NewPath);
           
recvStructFile true;
        }
  } else{
     
//Si no es una imagen mostramos el mensaje enviado
     
RichEdit1->SelStart RichEdit1->Text.Length();
     
RichEdit1->SelLength 0;
     
RichEdit1->SelAttributes->Color clGreen;
     
RichEdit1->Lines->Add(Socket->RemoteHost ": " AnsiString((char*)buffer).SubString(1,size) );  // Añadir los datos al memo de recepción
  
}
  
delete [] buffer;


Saludos.

escafandra 07-10-2014 22:16:16

Aprovecho para mostrarte como obtener el Hash MD5 de un archivo con la API de Windows tal y como lo utilicé en este ejemplo para cazar un virus: TerminateMD5_Process, a la caza de un virus...

Código PHP:

//---------------------------------------------------------------------------
#define MD5LEN  16
#define BUFSIZE 1024
typedef CHAR TMD5[33];


void GetMD5FromFile(CHARFileNameCHAR *MD5)
{
  
HANDLE hFile 0;
  
HCRYPTPROV hProv 0;
  
HCRYPTHASH hHash 0;
  
BYTE Hash[MD5LEN];
  
DWORD bHash 0;
  
DWORD bRead 0;
  
BYTEBuffer = (BYTE*)VirtualAlloc(0BUFSIZEMEM_COMMITPAGE_READWRITE);
  
hFile CreateFile(FileNameGENERIC_READFILE_SHARE_READNULLOPEN_EXISTINGFILE_FLAG_SEQUENTIAL_SCAN

NULL);
  if(
hFile != INVALID_HANDLE_VALUE){
    if(
CryptAcquireContext(&hProvNULLNULLPROV_RSA_FULLCRYPT_VERIFYCONTEXT)){
      if(
CryptCreateHash(hProvCALG_MD500, &hHash)){
        while (
1) {
          
ReadFile(hFileBufferBUFSIZE, &bReadNULL);
          if(!
bRead) break;
          
CryptHashData(hHashBufferbRead0);
        }
        
bHash MD5LEN;
        if(
CryptGetHashParam(hHashHP_HASHVALHash, &bHash0)){
          for(
int i=0i<2*MD5LENi++){
            
MD5[i] = (0x0F Hash[i/2] >> 4*((i+1)%2)) + 48;
            if(
MD5[i] > '9'MD5[i] += 7;
          }
          
MD5[32] = 0;
        }
      }
      
CryptDestroyHash(hHash);
    }
    
CryptReleaseContext(hProv0);
  }
  
CloseHandle(hFile);
  
VirtualFree(Buffer0MEM_RELEASE);


Saludos.

escafandra 07-10-2014 22:22:43

Un detalle más que olvidé al publicar la solución a tu problema es que ha añadido un guión bajo al nombre del archivo recibido puesto que se escribe en el mismo path que el original y puede ocurrir una doble apertura del mismo:
Código PHP:

NewPath ExtractFilePath(Application->ExeName) +"_"archivo.name


Saludos.

aguml 07-10-2014 23:29:56

estos dias no voy a poder tocar el pc porque voy a estar fuera y la verdad es que no veo el cambio que realizaste en el codigo a simple vista. ¿Podrias explicar que cambiaste y cual era el problema? Sobre lo del md5... Sabia que python lo ponia muy facil pero no sabia que la api de windows ya lo tenia y la verdad es que es de gran utilidad. Muchisimas gracias por todo.

escafandra 08-10-2014 00:33:51

Puse delante de todo, el código que lee el fichero, antes de las lecturas del flag y cabeceras. Viendo que esas variables eran globales, me salté su lectura, puesto que en el anterior evento ya se han leído.

El oroblema es que si lees del socket datos, cuando esperas un fichero, no se vuelven a leer después y pierdes esa información, que es del propio fichero.

Debes organizar un poco codo el código.


Saludos.

aguml 08-10-2014 13:09:04

ok amigo, mil gracias, ya contaré que tal va pero se me olvidó comentar algo y es que la funcion que pusiste para leer la llegada del fichero habia muy rara vez que salia antes de leer todo el fichero porque recibia un -1 antes de tiempo. Pude comprobar que si al final del bucle ponia un Sleep(1) ya no fallaba nunca. Ya digo que sin el Sleep fallaba muy rara vez, quizas una de 10 o mas veces. ¿por que podia pasar eso? la funcion transmitfile ya habia salido con true con lo que se supone que la cola de la que estamos descargando tiene ya todos los datos necesarios ¿no?

Otra cosa ¿Algun voluntario para probar si funciona online? es que solo lo he probado en mi pc y me gustaria ver como se hace para que funcione en online. ¿que pongo en TServerSocket->Host? ¿y que pongo en el cliente? ¿que diferencia hay entre Host, Address, y Service? Creo que en los tres puedo poner la direccion y funcionaria igual ¿no?


La franja horaria es GMT +2. Ahora son las 09:15:34.

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