[Delphi] TStream, winsock отправка

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by Redfern89, 2 Oct 2017.

  1. Redfern89

    Redfern89 New Member

    Joined:
    12 Jul 2012
    Messages:
    42
    Likes Received:
    1
    Reputations:
    -3
    Доброго времени суток! Как из TStream вытащить данные и через Winsock отправить их? Такой подход не помог
    Code:
      send(wSocket, Pointer(ASource)^, ASource.Size, 0);
    
    upd. Раобрался. Вот пример самой правильной на мой взгляд функции для загрузки/отправки данных по сокетам. Большое спасибо хочу выразить моему другу Xcentric за непосильную помощь! Данная функция прекрасно справляется со скачиванием файлов с сервера и отправкой их через multipart/form-data. Был тест на файлах 600мб

    Code:
    (* Процедура отправки/приема данных с сервера *)
    procedure THTTPSend.WSA_Send2(ip: string; Port: Integer; ASource: TStream; AResponse: TStream);
    var
      WSAData: TWSAData;
      SocketAddr: TSockAddr;
      recvBuffer: array[1..1024] of Char;
      wSocket: TSocket;
      Offset, RecvCount: Integer;
      DataSend: Int64;
      data_flag: boolean;
      Memory: array of Byte;
    begin
      // Инициализация модуля winsock
      if (WSAStartup(MakeWord(2, 2), WSAData) <> 0) Then // $202
      begin
        WriteLn('WinSock error');
        readln;
        exit;
      end;
    
      // Создание сокета со стандартными параметрами
      wSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
      if (wSocket = INVALID_SOCKET) Then
      begin
        WriteLn('Socket error');
        readln;
        exit;
      end;
    
      // Краткое описание протокола подключения
      SocketAddr.sin_family := AF_INET;
      SocketAddr.sin_port := htons(Port);
      SocketAddr.sin_addr.S_addr := inet_addr(PChar(IP));
    
      // Подключаемся к серверу
      if (Connect(wSocket, SocketAddr, SizeOf(SocketAddr)) <> 0) Then
      begin
        WriteLn('Connection error #', WSAGetLastError);
        readln;
        exit;
      end;
    
      // Шлем запрос частями (стд. размер буффера 8192)
      // Такое изъебство нужно для отправки больших файлов на сервер
      With ASource do
      begin
        ASource.Position := 0; // Ставим позицию на 0
        // Цикл, пока позиция меньше размера
        while (Position < Size) do
        begin
          // Длина буффера - либо указанная, либо оставшиеся - не переданные байты
          setLength(Memory, Min(FSendBufferLength, Size - Position));
          // Читаем данные из ASource и пишем их в буффер отправки
          ReadBuffer(Memory[0], Length(Memory));
          // Отправляем данные на сервер
          send(wSocket, Pointer(Memory)^, Length(Memory), 0);
        end;
      end;
    
      // Теперь считываем ответ от сервера
      data_flag := false; // Говорим, что данных пока нету
      repeat
        // Читаем по частям (1024)
        RecvCount := recv(wSocket, recvBuffer, SizeOf(recvBuffer), 0);
        if (RecvCount > 0) Then // Если есть, что считывать ...
        begin
          // Если данных нет, а только заголовки
          if (data_flag = false) Then
          begin
            // Ответ приходит с заголовками. Данные идут после двух пустых строк.
            // Надо как-раз найти позицию после второй пустой строки
            Offset := Pos(crlf + crlf, recvBuffer);
            // Запись первой части данных
            AResponse.WriteBuffer(recvBuffer[Offset +4], RecvCount - Offset - 3);
            // Говорим, что данные уже есть
            data_flag := true;
          end else
          begin
            // Продолжаем писать данные в буффер ответа
            AResponse.WriteBuffer(recvBuffer, RecvCount);
          end;
        end;
      // И так до тех пор, пока не будет че принимать с сервера
      until (RecvCount <= 0);
    
      // Закрываем сокет и сам модуль WinSock
      closesocket(wSocket);
      WSACleanup();
    end;
    
     
    #1 Redfern89, 2 Oct 2017
    Last edited: 4 Oct 2017