Recent

Author Topic: Enviar, recibir datos de un servidor  (Read 2156 times)

mav

  • Jr. Member
  • **
  • Posts: 79
Enviar, recibir datos de un servidor
« on: October 03, 2022, 10:11:15 pm »
Hola, que tal :
 Aquí tengo un servidor, el  más puro estilo MSDN, a este se conecta un cliente que
envía una cifra de 4 dígitos ej. (1234), he conseguido que se conecte el cliente, enviar los 4 dígitos
y recibir una respuesta...indeterminada :
Code: Pascal  [Select][+][-]
  1. program Server;
  2.  
  3. uses
  4.   windows,jwaws2tcpip,jwaWinSock2;
  5.  
  6. const
  7.   DEFAULT_PORT    = '55555';
  8.   DEFAULT_BUFLEN = 255;
  9.  
  10. var
  11.   recvbuf: array[0..DEFAULT_BUFLEN] of byte;
  12. //  i : Byte;
  13.   ret, recvbuflen  : integer;
  14.   SocketData       : TwsaData;
  15.   hints                : TAddrInfo;
  16.   Result,ptr         : PAddrInfo;
  17.   ListenSocket, ClientSocket : TSocket;
  18.   iResult, iSendResult          : Integer;
  19.  
  20.  // 1º Iniciar  Winsock ----------------------------------------------------------------------------
  21.  
  22. begin
  23.   Initialize(SocketData);
  24.   ret := WSAStartup(WINSOCK_VERSION,SocketData);
  25.   if ret <> 0 then
  26.   begin
  27.     WriteLn('WSAStartup failed: ', ret);
  28.     ExitProcess(1);
  29.   end
  30.   else
  31.     WriteLn('WSAStartup Ok');
  32.  
  33.   // 2º Crear un socket para el servidor-----------------------------------------------------------------
  34.  
  35.   Initialize(hints);
  36.  
  37.   hints.ai_family   := AF_INET;
  38.   hints.ai_socktype := SOCK_STREAM;
  39.   hints.ai_protocol := IPPROTO_TCP;
  40.   hints.ai_flags    := AI_PASSIVE;
  41.  
  42.   Result := nil;
  43.  
  44.   iResult := getaddrinfo(nil,DEFAULT_PORT,@hints, Result);
  45.   if iResult <> 0 then
  46.   begin
  47.     WriteLn('getaddrinfo failed : ', iResult);
  48.     WSACleanup;
  49.     ExitProcess(1);
  50.   end;
  51.   if Result = nil then
  52.   begin
  53.     WriteLn('MemAlloc Error');
  54.     Exit;
  55.   end;
  56.  
  57.   ptr := Result;
  58.   ListenSocket := INVALID_SOCKET;
  59.  
  60.   ListenSocket := socket(ptr^.ai_family,ptr^.ai_socktype,ptr^.ai_protocol);
  61.   if ListenSocket = INVALID_SOCKET then
  62.   begin
  63.     WriteLn('Error at socket(): ',WSAGetLastError);
  64.     freeaddrinfo(Result);
  65.     WSACleanup;
  66.     ExitProcess(1);
  67.   end;
  68.  
  69.  // 3º Binding (enlazar) el socket -----------------------------------------------------------
  70.  
  71.   iResult := bind(ListenSocket, ptr^.ai_addr, Integer(ptr^.ai_addrlen));
  72.   if iResult = SOCKET_ERROR then
  73.   begin
  74.     WriteLn('bind failed with error: ', WSAGetLastError);
  75.     freeaddrinfo(result);
  76.     closesocket(ListenSocket);
  77.     WSACleanup;
  78.     ExitProcess(1);
  79.   end;
  80.  
  81.   // 4º Listening on a socket, escuchando...-----------------------------------------------------
  82.  
  83.   if listen( ListenSocket, SOMAXCONN ) = SOCKET_ERROR then
  84.   begin
  85.     WriteLn('Listen failed with error: ', WSAGetLastError);
  86.     closesocket(ListenSocket);
  87.     WSACleanup;
  88.     ExitProcess(1);
  89.   end;
  90.  
  91.   // 5º Aceptando una conexión-----------------------------------------------------------------
  92.  
  93.   ClientSocket := INVALID_SOCKET;
  94.  
  95.   ClientSocket := accept(ListenSocket, nil, nil);
  96.   if ClientSocket = INVALID_SOCKET then
  97.   begin
  98.     WriteLn('accept failed: ', WSAGetLastError);
  99.     closesocket(ListenSocket);
  100.     WSACleanup;
  101.     ExitProcess(1);
  102.   end;
  103.  
  104.   // 6º Recibiendo y enviando datos............-----------------------------------------------------------
  105.  
  106.   recvbuflen := DEFAULT_BUFLEN;
  107.  
  108.   Initialize(recvbuf);
  109.   repeat
  110.     iResult := recv(ClientSocket, recvbuf, recvbuflen, 0);
  111.     if iResult > 0 then
  112.     begin
  113.       WriteLn('Bytes received: ', iResult);
  114.  
  115.       //--WriteLn los bytes recibidos (el número de ellos está en iResult(4)), que van a ser una parte de recvbuf  ¿Como?
  116.  
  117.  
  118.       //--Operar con los bytes recibidos y enviarlos al cliente ¿Como?
  119.  
  120.  
  121.       iSendResult := send(ClientSocket, recvbuf, iResult, 0);
  122.       if iSendResult = SOCKET_ERROR then
  123.       begin
  124.         WriteLn('send failed: ', WSAGetLastError);
  125.         closesocket(ClientSocket);
  126.         WSACleanup();
  127.         Exit;
  128.       end;
  129.       WriteLn('Bytes sent: ', iSendResult);
  130.     end
  131.     else
  132.     if iResult = 0 then
  133.     begin
  134.       WriteLn('Connection closing...');
  135.     end
  136.     else
  137.     begin
  138.       WriteLn('recv failed: ', WSAGetLastError());
  139.       closesocket(ClientSocket);
  140.       WSACleanup();
  141.       Exit;
  142.     end;
  143.   until iResult <= 0;
  144.  
  145.  // 7º Desconectando el servidor ---------------------------------------------------------------------------
  146.  
  147.   iResult := shutdown(ClientSocket, SD_SEND);
  148.   if iResult = SOCKET_ERROR then
  149.   begin
  150.     WriteLn('shutdown failed with error: ', WSAGetLastError());
  151.     closesocket(ClientSocket);
  152.     WSACleanup();
  153.     Exit;
  154.   end;
  155.  
  156.   // cleanup
  157.   closesocket(ClientSocket);
  158.   WSACleanup();
  159. end.
  160.  
  161.  
Las preguntas son:
  1- ¿Como podria escribir (WriteLn) los dígitos enviados por el cliente, para comprobar que está bien? y
  2- La respuesta que tengo que enviar es :
     (Los dos primeros dígitos XOR hora actual) + (Los tercero y cuarto digito Xor minuto actual)
    ...esto último casi lo tengo ya experimentando con DecodeTime un poco.
    ¿Como separo los dátos de dos en dos, para operar con ellos?

Code: Pascal  [Select][+][-]
  1. Program project1;
  2. { This program demonstrates the DecodeTime function }
  3.  
  4. Uses sysutils;
  5. Var HH,MM,SS,MS, sumad, sumad2, sumad3: Word;
  6.  
  7. Begin
  8.   DecodeTime(Time,HH,MM,SS,MS);
  9.   Writeln (format('The time is %d:%d:%d.%d',[hh,mm,ss,ms]));
  10.  
  11.  
  12.   //---------------------------------------
  13.   WriteLn(format('%d%d', [hh,mm])) ;      //
  14.                                           //
  15.   sumad := hh xor 12 ;                    //
  16.   WriteLn (format('%d', [sumad]));        //
  17.                                           //
  18.   sumad2 := mm xor 34 ;                   //
  19.   WriteLn (format('%d', [sumad2]));       //
  20.   //---------------------------------------
  21.  
  22.   sumad3 := sumad+ sumad2;
  23.   WriteLn (format('%d', [sumad3]));
  24.   WriteLn(#13#10#13#10#13#10);
  25.  
  26.   WriteLn (format('%d%d', [sumad,sumad2]));
  27.  
  28.   ReadLn;
  29. End.
  30.  

Un saludo a todos y gracias.

Edson

  • Hero Member
  • *****
  • Posts: 1296
Re: Enviar, recibir datos de un servidor
« Reply #1 on: October 04, 2022, 12:12:13 am »
Las preguntas son:
  1- ¿Como podria escribir (WriteLn) los dígitos enviados por el cliente, para comprobar que está bien? y
  2- La respuesta que tengo que enviar es :
     (Los dos primeros dígitos XOR hora actual) + (Los tercero y cuarto digito Xor minuto actual)
    ...esto último casi lo tengo ya experimentando con DecodeTime un poco.
    ¿Como separo los dátos de dos en dos, para operar con ellos?

1) No he usado jwaws2tcpip o jwaWinSock2 (¿Es Jedi?) pero se puede ver que lo que buscas debe estar en "recvbuf". Tal vez puedas encontrar algún ejemplo en la documentación o en páginas equivalentes. Si no encuentras en Lazarus, te puedes guiar de los ejemplos de Delphi.
2) Para separar una cadena, puedes usar la función copy() y tomar dos subcadenas de la cadena original. En tu caso las subcadenas serían '12' y '34'. Luego tienes que convertir esas cadenas a número si quieres aplicarles el XOR.
Lazarus 2.2.6 - FPC 3.2.2 - x86_64-win64 on Windows 10

mav

  • Jr. Member
  • **
  • Posts: 79
Re: Enviar, recibir datos de un servidor
« Reply #2 on: October 04, 2022, 02:12:45 am »
...jwaws2tcpip o jwaWinSock2 es Api de Windows, que uso porque en winsock no hay convertidas algunas estructuras y declaraciones del api
que si están en el jwa..El problema es, después de que al buffer (recvbuf: array[0..DEFAULT_BUFLEN] of byte;) le han llegado del servidor los 4 bytes.
¿Como los leo y posteriormente selecciono de dos en dos para operar con ellos :
Code: Pascal  [Select][+][-]
  1.                i: char?, string?,
  2.  
  3.                i:= Copy(recvbuf, 1,4);  //Evidentemente esto no se puede hacer pero sería lo que quiero
  4.                WriteLn(i);            
  5.  
         
 

mosquito

  • Full Member
  • ***
  • Posts: 138
Re: Enviar, recibir datos de un servidor
« Reply #3 on: October 04, 2022, 09:53:45 am »
Quizás podrías mandar desde el cliente en vez de '1234' algo como ':#1234'.
Después usar (PosEx(':#',vbuf)+1) y copiar los 4 bytes contiguos. Así podrías mandar datos con cualquier formato y poder encontrar tus 4 bytes siempre independientemente de donde se encuentren en el buffer.

USES
classes, sysutils, strutils;
« Last Edit: October 04, 2022, 09:56:46 am by mosquito »

Edson

  • Hero Member
  • *****
  • Posts: 1296
Re: Enviar, recibir datos de un servidor
« Reply #4 on: October 04, 2022, 04:11:15 pm »
...jwaws2tcpip o jwaWinSock2 es Api de Windows, que uso porque en winsock no hay convertidas algunas estructuras y declaraciones del api
que si están en el jwa..El problema es, después de que al buffer (recvbuf: array[0..DEFAULT_BUFLEN] of byte;) le han llegado del servidor los 4 bytes.
¿Como los leo y posteriormente selecciono de dos en dos para operar con ellos :
Code: Pascal  [Select][+][-]
  1.                i: char?, string?,
  2.  
  3.                i:= Copy(recvbuf, 1,4);  //Evidentemente esto no se puede hacer pero sería lo que quiero
  4.                WriteLn(i);            
  5.  
       

No puedes aplicar copy() a un arreglo de bytes como es "recvbuf". Tal vez si fuera un arreglo de "char". Puedes probar, tal vez te acepte usar un arreglo de char en lugar de bytes.
Otra opción sería, si sabes que tienes los datos en un arreglo de bytes y sabes que te deben llegar 4 bytes (porque se deduce que deben ser 4 caracteres de acuerdo a lo que indicas), lo más facil sería hacer algo como:

Code: Pascal  [Select][+][-]
  1. var parte1, parte2: string;
  2. ...
  3. parte1 := chr(recvbuf[0]) + chr(recvbuf[1]) ;
  4. parte2 := chr(recvbuf[2]) + chr(recvbuf[3]) ;
  5.  

No es la forma más elegante, pero creo que se entiende la idea. Por si acaso no he probado el código, solo lo escribo de memoria.

Yo escribí una librería que trabaja con sockets, pero usa Synapse. Tal vez te pueda servir: https://github.com/t-edson/conSock/blob/0.5/conSockClient.pas



 
« Last Edit: October 04, 2022, 04:14:42 pm by Edson »
Lazarus 2.2.6 - FPC 3.2.2 - x86_64-win64 on Windows 10

mav

  • Jr. Member
  • **
  • Posts: 79
Re: Enviar, recibir datos de un servidor
« Reply #5 on: October 07, 2022, 12:07:54 am »
Hola buenas noches, ya lo conseguí:   :) :)
Code: Pascal  [Select][+][-]
  1.    // añadido un uses : sysutils
  2.    var
  3.   //recvbuf: array[0..DEFAULT_BUFLEN] of byte; cambié el array a char ,el mismo tamaño
  4.  
  5.   recvbuf: array[0..DEFAULT_BUFLEN] of Char;
  6.     // unas variables mas
  7.   i, j, k : string ;
  8.   suma1, suma2 : integer;
  9.   HH,MM,SS,MS  : WORD ;      
  10.   ................
  11. .................
  12.   // y por último este code:
  13.  
  14.         i:= Copy( recvbuf , 1, iResult);
  15.         WriteLn(i);
  16.  
  17.         j:= Copy( i, 1, 2);
  18.         k:= Copy( i, 3, 4);
  19.  
  20.         DecodeTime(Time,HH,MM,SS,MS);  //por esto el sysutils
  21.          suma1             := StrToInt(j) xor HH ;
  22.          suma2             := StrToInt(k) xor MM ;
  23.          recvbuf           := IntToStr( suma1 + suma2) ;        
  24.                  
  25.                  //..y funcionando
  26.  
Saludos y gracias

 

TinyPortal © 2005-2018