CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - HttpWebRequest i wysyłka przez POST

HttpWebRequest i wysyłka przez POST

problemy z tworzeniem programów do obsługi sieci, internetu, e-mail itp..

HttpWebRequest i wysyłka przez POST

Nowy postprzez Slynx » poniedziałek, 8 sierpnia 2011, 00:36

KOD cpp:     UKRYJ  
HttpWebRequest^ request = dynamic_cast<HttpWebRequest^>(WebRequest::Create(url));
// ... poustawianych kilka właściwości...
request->AllowWriteStreamBuffering = true;
Upload^ up = gcnew Upload(request->GetRequestStream());  
up->Start();
HttpWebResponse^ response = dynamic_cast<HttpWebResponse^>(request->GetResponse());
 


gdzie klasa Upload to ...
KOD cpp:     UKRYJ  
Void Upload::Start()
{
// data - strumień zawierający dane do wysyłki
// write_stream = request->GetRequestStream();
int bytes = 0;
array<unsigned char>^ buffer = gcnew array<unsigned char>(8192);
                       
while ((bytes = data->Read(buffer, 0, buffer->Length)) > 0)
{
        write_stream->Write(buffer, 0, bytes);
        this->upd_->Invoke(data->Position);
}
write_stream->Close();
MessageBox::Show("Completed");
};
 

Problem jest z momentem zapisu danych do strumienia. Jak sądziłem zapis do strumienia nie będzie się zbytnio różnił od odczytu, jednak się pomyliłem. Dane wysyłane są w momencie wywołania
KOD cpp:     UKRYJ  
HttpWebResponse^ response = dynamic_cast<HttpWebResponse^>(request->GetResponse());
co powoduje natychmiastowe pokazanie się napisu "Completed" a następnie zatrzymanie programu, ponieważ wywoływana jest funkcja GetResponse(), która zamiast tylko odebrać odpowiedź, wcześniej wysyła cały strumień.

Z tego co mi wiadomo, jednym z możliwych rozwiązań jest użycie BeginWrite i EndWrite, jednak to jest równoznaczne z tworzeniem kodu wykonujące się asynchronicznie, a nie na tym mi aktualnie zależy (na końcu dam całą funkcję wysyłającą na wątek - o ile to się sprawdzi, bo już mam co do tego wątpliwości). Na msdn pisało też, że aby od razu zapisywać do strumienia należy ustawić właściwość "AllowWriteStreamBuffering" na false, ustawiłem - zero efektu.
Jak to zrobić ? Jak zmusić ten kod by wysyłał dane od razu, a nie gromadził w kolejnym buforze (to ma coś wspólnego z sendChunked ?)
Avatar użytkownika
Slynx
Mądrosław
Mądrosław
 
Posty: 350
Dołączył(a): piątek, 17 grudnia 2010, 21:59
Podziękował : 11
Otrzymał podziękowań: 0
System operacyjny: Windows 7 32
Kompilator: Visual C++ 2005; Visual C++ 2008; Visual C++ 2010; Visual C# 2010;
Gadu Gadu: 0
    Windows 7Chrome

Re: HttpWebRequest i wysyłka przez POST

Nowy postprzez polymorphism » poniedziałek, 8 sierpnia 2011, 10:01

Nie wiem, czy coś to da, ale spróbuj przed wtłaczaniem danych do strumienia ustawić właściwość ContentLength. Być może jeśli będzie wiadomo, ile danych trzeba wysłać, wysyłanie będzie odbywać się na bieżąco - teraz HttpWebRequest tego nie robi, bo nie wie, ile tych danych będzie, więc czeka na zamknięcie strumienia, żeby określić ich ilość. Wiedza o ilości danych jest potrzebna do wygenerowania odpowiednich nagłówków HTTP.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: HttpWebRequest i wysyłka przez POST

Nowy postprzez Slynx » poniedziałek, 8 sierpnia 2011, 11:48

Powinienem był dać troszkę więcej kodu, ale nie myślałem, że to jest istotne. Jeszcze to jest ustawiane (w miejscu komentarza - "// ... poustawianych kilka właściwości...")
KOD cpp:     UKRYJ  
                        request->ContentType = "multipart/form-data; boundary=" + this->MPF_boundary;
                        request->Referer = this->Referer;
                        request->Method = "POST";
                        request->AutomaticDecompression = System::Net::DecompressionMethods::GZip;
                        request->AllowAutoRedirect = AllowAutoRedirect;

                        request->CookieContainer = cookies_;
                        //ServicePointManager::Expect100Continue = Expect100Continue;
                        ServicePointManager::Expect100Continue = true;

                        request->Accept = Accept;
                        request->UserAgent = UserAgent;

                        if (CacheControlMaxAge0_ == true)  request->Headers->Add(HttpRequestHeader::CacheControl, "max-age=0");
                        request->Headers->Add(HttpRequestHeader::KeepAlive, KeepAlive.ToString()->ToLower());
                        request->Headers->Add(HttpRequestHeader::AcceptCharset, AcceptCharset);
                        request->Headers->Add(HttpRequestHeader::AcceptEncoding, AcceptEncoding);
                        request->Headers->Add(HttpRequestHeader::AcceptLanguage, AcceptLanguage);

                        request->KeepAlive = KeepAlive;

                        array<Byte>^ x = System::Text::Encoding::ASCII->GetBytes(this->MPF_boundary + "\r\n");
                        this->MPF_body->Write(x, 0, x->Length);

                        request->ContentLength = this->MPF_body->Length;
 

Tu jest ustawianych trochę właściwości dopasowanych do MPF. Z czym się waham. Expect100Contiune. Podobno może powodować błąd przy wysyłaniu POST-a jako MPF. SendChunked - na kilku forach pisało, że ustawienie tej właściwości na true, pozwala wysyłać dane w kawałkach - owszem, ale nie każdy serwer może obsługiwać coś takiego, więc to nie jest rozwiązanie. Znalazłem też rozwiązanie w którym ustawienie AllowWriteStreamBuffering na false rozwiązywało problem. Jednak to nie prawda. Na msdn można wyczytać, że jest to coś w rodzaju dodatkowego bufora, ale wyłączenie go i tak nie zmusi do natychmiastowego zapisu danych do strumienia.
MPF_body jest strumieniem pamięciowym (Twój pomysł) z całymi danymi.

Przegrzebałem ze 30 stron i nie znalazłem nic sensownego, za każdym razem rozwiązaniem jest wykorzystanie BeginGetResponse i EndGetResponse, ale mnie takie rozwiązanie nie satysfakcjonuje, bo nie chcę by wysyłka była realizowana nawet częściowo asynchronicznie.
Avatar użytkownika
Slynx
Mądrosław
Mądrosław
 
Posty: 350
Dołączył(a): piątek, 17 grudnia 2010, 21:59
Podziękował : 11
Otrzymał podziękowań: 0
System operacyjny: Windows 7 32
Kompilator: Visual C++ 2005; Visual C++ 2008; Visual C++ 2010; Visual C# 2010;
Gadu Gadu: 0
    Windows 7Chrome

Re: HttpWebRequest i wysyłka przez POST

Nowy postprzez polymorphism » poniedziałek, 8 sierpnia 2011, 15:16

Znalazłem też rozwiązanie w którym ustawienie AllowWriteStreamBuffering na false rozwiązywało problem. Jednak to nie prawda. Na msdn można wyczytać, że jest to coś w rodzaju dodatkowego bufora, ale wyłączenie go i tak nie zmusi do natychmiastowego zapisu danych do strumienia.

No dobra, ale to może być mały bufor, który będzie dość często flushowany. Nie przejmowałbym się tym.

p.s. AllowWriteStreamBuffering będzie działać tylko w połączeniu z ustawionym ContentLenght.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: HttpWebRequest i wysyłka przez POST

Nowy postprzez Slynx » poniedziałek, 8 sierpnia 2011, 19:36

Jak mały ? To ma znaczenie. Co ile wykonywanu flush ? 32 KB ? 64 ? Plik miał 300 KB. Jeśli masz rację, to bufor musiałby być większy niż 300 KB, a to chyba mało prawdopodobne (odświeżanie co 300 KB ? Trochę duże odstępy). Chyba, że jest możliwość zmiany rozmiaru tego bufora. A contentLength jak widziałeś, zawsze jest ustawiany. Jednak ustawiałem tą opcję i na true i na false - żadnego efektu nie było. I tak dane wysyłał w momencie wywołania GetResponse().

(Choć tu w pewnym momencie sie zawahałem, bo chyba nie do końca. Jeśli dobrze zauważyłem i breakpoint był właściciwe umieszczony, to dane zaczyna wysyłać po wywołaniu Close() na strumieniu, a zacina się przy GetResponse(), bo funkcja oczekuje aż wszystkie dane zostaną wysłane i możliwe będzie odebranie odpowiedzi od serwera. Jednak jeśli to prawda, to wystarczyło by w tej pętli wywoływać flush po każorazowym zapisie do strumienia i powinien dopisywać do strumienia (wysyłać dane), a tak się nie dzieje, bo już próbowałem to zrobić) .
Chyba żeby ustawić AllowWriteStreamBuffering na false i w pętli dodać flush na strumieniu. Nie wiem czy to by coś zmieniło... (na razie sprawdzić nie mogę, zreinstalowałem system i intaluje sterowniki, itp. to potrwa pewnie ze 2 dni na moim necie)
Avatar użytkownika
Slynx
Mądrosław
Mądrosław
 
Posty: 350
Dołączył(a): piątek, 17 grudnia 2010, 21:59
Podziękował : 11
Otrzymał podziękowań: 0
System operacyjny: Windows 7 32
Kompilator: Visual C++ 2005; Visual C++ 2008; Visual C++ 2010; Visual C# 2010;
Gadu Gadu: 0
    Windows 7Internet Explorer 8

Re: HttpWebRequest i wysyłka przez POST

Nowy postprzez Slynx » sobota, 13 sierpnia 2011, 13:18

To nie funkcja GetResponse() wstrzymuje działanie, tzn. nie do końca. Pobawiłem się w bardziej szczegółowe debugowanie. Zapis danych jest wykonywany w momencie zapisu do strumienia, jednak zapisuje do tego strumienia z maksymalną szybkością (odczyt z dysku), a jako, że internet jest wolniejszy to resztę buforuje. Bufor jest duży, załadował do niego plik o wielkości 200MB. Szukam jakichś dodatkowych informacji, ale na ten temat w necie jest na prawdę ciężko. Gdyby udało się odczytać aktualną pozycję w strumieniu lub od razu - liczbę rzeczywiście zapisanych bajtów - można by uruchomić na oddzielnym wątku timer i np. co 2 sekundy pobierać aktualną pozycje / ilość zapisanych bajtów. Coś takiego jak Position nie działa, rzuca wyjątkiem "strumień nie obsługuje operacji szukania". Asynchroniczny zapis do tego strumienia też najprawdopodobniej nic by nie dał, zapisał by tak samo, od razu, bo wszystko i tak zostałoby zbuforowane. Przeprowadzenie tego na GetResponse(), czyli Begin i End-GetResponse(), też nie dałoby efektu, bo odpowiedź z serwera miałaby np. 50 KB, a rozpoczęcie odczytu zacznie się dopiero od momentu wysłania całego żądania, tak więc asynchronicznie przerzuciłbym jedynie te 50 KB, a wcześniej i tak czekał na wysyłkę danych. Rozejrzałem się już nawet nad opcją przejścia na WebClient ale tamte metody umożliwiają wysyłkę jedynie pod konkretne url, a w moim przypadku lepszy byłby zapis pod strumień - jednak WebClient to ostateczność, więc na razie tego nie ruszam.

Aktualnie nie mam już pomysłów, szukam dalej w google :/
Avatar użytkownika
Slynx
Mądrosław
Mądrosław
 
Posty: 350
Dołączył(a): piątek, 17 grudnia 2010, 21:59
Podziękował : 11
Otrzymał podziękowań: 0
System operacyjny: Windows 7 32
Kompilator: Visual C++ 2005; Visual C++ 2008; Visual C++ 2010; Visual C# 2010;
Gadu Gadu: 0
    Windows 7Chrome

Re: HttpWebRequest i wysyłka przez POST

Nowy postprzez polymorphism » sobota, 13 sierpnia 2011, 14:17

No, zawsze możesz użyć funkcji WinApi, a dokładniej biblioteki wininet (HttpSendRequest itd.). Tu, na forum, było parę tematów związanych z tą biblioteką.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: HttpWebRequest i wysyłka przez POST

Nowy postprzez Slynx » niedziela, 14 sierpnia 2011, 21:58

A jesteś pewien, że ta funkcja z tej biblioteki na pewno będzie działać inaczej ?
Avatar użytkownika
Slynx
Mądrosław
Mądrosław
 
Posty: 350
Dołączył(a): piątek, 17 grudnia 2010, 21:59
Podziękował : 11
Otrzymał podziękowań: 0
System operacyjny: Windows 7 32
Kompilator: Visual C++ 2005; Visual C++ 2008; Visual C++ 2010; Visual C# 2010;
Gadu Gadu: 0
    Windows 7Chrome

Re: HttpWebRequest i wysyłka przez POST

Nowy postprzez polymorphism » niedziela, 14 sierpnia 2011, 22:40

Sprawdź, będziesz wiedział. Nie przewiduje problemów z niepotrzebnym buforowaniem, ale kto tam wie, co Ty tam tak naprawdę robisz... :)
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: HttpWebRequest i wysyłka przez POST

Nowy postprzez Slynx » sobota, 29 października 2011, 14:06

No, polymorphism, muszę się pochwalić (w drugim temacie również ;p). Rozwiązałem. Pomocne okazało się użycie klasy BufferedStream (nie wiedziałem, że taka istnieje). Sturmień jest od początku zbuforowany i można sobie wysyłać po kawałku co pozwala nam wprowadzić pasek postępu ;)
Tak czy inaczej, dzięki za pomoc i za Twój czas.
Avatar użytkownika
Slynx
Mądrosław
Mądrosław
 
Posty: 350
Dołączył(a): piątek, 17 grudnia 2010, 21:59
Podziękował : 11
Otrzymał podziękowań: 0
System operacyjny: Windows 7 32
Kompilator: Visual C++ 2005; Visual C++ 2008; Visual C++ 2010; Visual C# 2010;
Gadu Gadu: 0
    Windows 7Chrome


  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Aplikacje sieciowe

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 2 gości

cron