• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

[C++] server nie czeka na \n i od razu zwraca wynik.

Object Storage Arubacloud
0 głosów
507 wizyt
pytanie zadane 11 czerwca 2018 w C i C++ przez Hiskiel Pasjonat (22,830 p.)
edycja 11 czerwca 2018 przez Hiskiel

Witam.

 

Napisałem sobie serwer TCP w WinSock (z racji, iż to moje pierwsze sieciowe przedsięwzięcie to korzystałem z poradnika, https://www.youtube.com/watch?v=WDn-htpBlnU). Póki co miał zwracać to co napisał użytkownik, jak na filmie, jednakże ten zwraca wszystko od razu, jak na screenie https://i.imgur.com/fKW4Bar.png.   (Hasła oczywiście zaszyfrowane ;d, jeśli ktoś to zauważył)

Nie wiem co może być przyczyną.

Myślałem, żeby zrobić jedną zmienną char która będzie dołączana do całego stringa aż do napotkania znaku '\n' ale nie wiem czy tak po prostu musiałbym zrobić, czy jest to jakiś błąd. Facet z filmiku nie musiał tak robić.

 

Dodatkowo mam parę pytań, a żeby nie zaśmiecać serwisu zadam je w tym wątku. Na screenie widać, że po stronie klienta (po stronie serwera również, ale to już logi) jest wypisywane " connected (liczba)". Pusta przestrzeń jest tam dlatego, że przed connected ma być nazwa hosta, która nie jest wyświetlana. liczba to port, jednakże nie wiem dlaczego jest inny niż port przez który się łączę i to jest pytanie pierwsze - dlaczego ten port jest inny. Drugim pytaniem jest czy jest wiadome dlaczego ta nazwa nie jest wyświetlana? Trzecim - na screenie widać, że ten napis Wwiittaamm czy ssiieemmaa są z dziwnym odstępem - kiedy po połączeniu wysyłam do klienta ten napis connected to taka wyrwa jest, jeśli nie wysyłam jest git. Teraz zrobiłem, że wysyła kolejny tekst z napisem składającym się z \b (jest ich tyle ile ma znaków wiadomość connected) ale wątpię czy jest to dobry sposób.

 

Jeśli ktoś byłby w stanie mi pomóc to bardzo dziękuję. Za wszelkie niedociągnięcia z góry przepraszam, w razie czego proszę się pytać.

 

Pozdrawiam.

 

PS tutaj cały kod:

//pętla while od 71 linii
#include <iostream>
#include <WS2tcpip.h>
#include <winsock2.h>
#include <thread>
#include <chrono>
#include <sstream>
#include <ctime>

#pragma comment(lib, "ws2_32.lib")

std::string LogInfo();

int main(){
    WSADATA wData;
    std::cout<< LogInfo() <<"Initializing server...\n";
    if(WSAStartup(MAKEWORD(2,2), &wData)!=0){
        std::cout<< LogInfo() <<"Cannot initialize server. (WSADATA)\n";
        return 1;
    }

    SOCKET ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(ListeningSocket == INVALID_SOCKET){
        std::cout<<"Cannot initialize server. (SOCKET)\n";
        return 2;
    }

    sockaddr_in address;
    address.sin_addr.S_un.S_addr = INADDR_ANY;
    address.sin_family = AF_INET;
    address.sin_port = htons(55555);

    bind(ListeningSocket, reinterpret_cast<sockaddr*>(&address), sizeof(address));

    std::cout<< LogInfo() <<"Server is ready. Waiting for connection.\n";
    listen(ListeningSocket, SOMAXCONN);
    sockaddr_in client;
    int ClientSize = sizeof(client);
    SOCKET ClientSocket = accept(ListeningSocket, reinterpret_cast<sockaddr*>(&client), &ClientSize);
    if(ClientSocket == INVALID_SOCKET){
        std::cout<<"Cannot connect with user\n";
        return 3;
    }

    char host[NI_MAXHOST];
    char port[NI_MAXSERV];
    memset(host, 0, NI_MAXHOST);
    memset(port, 0, NI_MAXSERV);

    std::string message;
    if(getnameinfo(reinterpret_cast<sockaddr*>(&ClientSocket), sizeof(ClientSocket), host, NI_MAXHOST, port, NI_MAXSERV, 0) == 0){
         std::stringstream PortInStr;
         PortInStr << port;
         message = std::string(host) + " conected. ("+PortInStr.str()+")\n";
    }else{
         inet_ntoa(client.sin_addr);
         std::stringstream PortInStr;
         PortInStr << htons(client.sin_port);
         message = std::string(host) + " connected. ("+std::string(PortInStr.str())+")\n";
    }

    std::string back;
    for(int i=0;i<message.length();++i) back.append("\b");
    std::cout<< LogInfo() <<message;
    send(ClientSocket, message.c_str(), message.length(), 0);
    send(ClientSocket, back.c_str(), back.length(), 0);

    closesocket(ListeningSocket);

    char UserInput[2048];

    while(true){
        memset(UserInput, 0, 2048);

        int ReceivedBytes = recv(ClientSocket, UserInput, 2048, 0);
        if(UserInput[0]>32)
            std::cout<< LogInfo() <<UserInput<<"\n";

        if(ReceivedBytes == SOCKET_ERROR){
            std::cout<<"Cannot receive input.\n";
            break;
        }if(ReceivedBytes == 0){
            std::cout<<"Client disconnected.\n";
            std::this_thread::sleep_for(std::chrono::seconds(3));
            break;
        }
        send(ClientSocket, UserInput, ReceivedBytes+1, 0);

    }

    closesocket(ClientSocket);

    WSACleanup();
}

std::string LogInfo(){
    time_t rawtime = time(0);
    std::tm* now = localtime(&rawtime);
    std::stringstream time;
    std::string month, day, hour, minute, second;

    if(std::to_string(now->tm_mon).length()==1) month = '0';
    if(std::to_string(now->tm_mday).length()==1) day = '0';
    if(std::to_string(now->tm_hour).length()==1) hour = '0';
    if(std::to_string(now->tm_min).length()==1) minute = '0';
    if(std::to_string(now->tm_sec).length()==1) second = '0';
    month += std::to_string(now->tm_mon);
    day += std::to_string(now->tm_mday);
    hour += std::to_string(now->tm_hour);
    minute += std::to_string(now->tm_min);
    second += std::to_string(now->tm_sec);

    time<<now->tm_year+1900<<"-"<<month<<"-"<<day<<" "<<hour<<":"<<minute<<":"<<second<<">  ";

    return time.str();
}

 

1 odpowiedź

+1 głos
odpowiedź 11 czerwca 2018 przez j23 Mędrzec (194,920 p.)
wybrane 25 czerwca 2018 przez Hiskiel
 
Najlepsza

Jakoś tak bym zrobił:

int ReceivedBytes;
std::string recv_text;


while((ReceivedBytes = recv(ClientSocket, UserInput, 2048, 0)) > 0)
{
	auto it2 = UserInput + ReceivedBytes;
	auto it1 = std::find(UserInput, it2, '\n');
	recv_text.append(UserInput, it1);
	if(it1 != it2)
	{	std::cout<< LogInfo() << recv_text << '\n';
		send(ClientSocket, recv_text.c_str(), recv_text.size(), 0);
	}
}

if(ReceivedBytes == SOCKET_ERROR)
{
	std::cout<<"Cannot receive input.\n";
	break;
}
else if(ReceivedBytes == 0)
{
	std::cout<<"Client disconnected.\n";
	std::this_thread::sleep_for(std::chrono::seconds(3));
	break;
}

jednakże nie wiem dlaczego jest inny niż port przez który się łączę

Dlatego że port, na który się łączysz, jest dla socketa nasłuchującego. Socket zwrócony przez accept ma inny losowy port, dzięki czemu serwer jest w stanie obsługiwać kilka(set) połączeń na raz.

 

// EDIT

Nie prościej tak:

std::string LogInfo()
{
    std::ostringstream oss;
    time_t t = time(0);
    oss << std::put_time(std::localtime(&t), "%D %T") << "> ";
    return oss.str();
}

?

komentarz 11 czerwca 2018 przez Hiskiel Pasjonat (22,830 p.)
No tak, prościej, ale czy to doda zera na początek?

Dodatkowo, czy znasz odpowiedź na inne pytania, zależałoby mi na odpowiedzi, oczywiście do niczego nie zmuszam.

I takie pytanie, co oznacza wyrażenie char[] + int? UserInput + ReceivedBytes
komentarz 12 czerwca 2018 przez j23 Mędrzec (194,920 p.)
edycja 12 czerwca 2018 przez j23

ale czy to doda zera na początek?

Tam masz format string, poczytaj dokumentację i pokombinuj.

 

co oznacza wyrażenie char[] + int?

Jeśli wskaźnik potraktujesz jak iterator, to wyrażenie UserInput + ReceivedBytes znaczy to samo co iterator .end().

 

Odnośnie nazwy hosta:

SOCKET ClientSocket = /* ... */

if(getnameinfo(reinterpret_cast<sockaddr*>(&ClientSocket), sizeof(ClientSocket), /* ... */) == 0)

Dlaczego w pierwszym parametrze na chama dajesz socketa zamiast dać zgodnie z dokumentacją adres do struktury sockaddr_in lub sockaddr_in6?

 

std::string back;

for(int i = 0; i < message.length(); ++i) back.append("\b");

Nie prościej tak:

std::string back(message.length(), '\b');

? :)

 

Jeśli chodzi o te odstępy, zamiast \n wysyłaj \r\n.

komentarz 12 czerwca 2018 przez Hiskiel Pasjonat (22,830 p.)
Dobra, dzięki za pomoc, jednakże ten "lepszy" sposób jeśli chodzi o funkcję LogInfo nie działa.
komentarz 12 czerwca 2018 przez j23 Mędrzec (194,920 p.)
edycja 12 czerwca 2018 przez j23

Jak nie działa, jak działa -> link

 

 

komentarz 12 czerwca 2018 przez Hiskiel Pasjonat (22,830 p.)

Dalej nie działało, ale nie ważne. Zamiast %D %T trzeba było wpisać %Y-%m-%d %H:%M:%S

Dodatkowo mam inny problem. Kompilator nie wie za co brać ClientInput jako char[2048] + int i nici z tego :/.

main.cpp:75:52: error: no matching function for call to 'find(char [2048], char*
&, char)'
         auto it2 = std::find(ClientInput, it1, '\n');
                                                    ^
In file included from D:/mingw-w64/i686-7.3.0-posix-dwarf-rt_v5-rev0/mingw32/lib
/gcc/i686-w64-mingw32/7.3.0/include/c++/bits/locale_facets.h:48:0,
                 from D:/mingw-w64/i686-7.3.0-posix-dwarf-rt_v5-rev0/mingw32/lib
/gcc/i686-w64-mingw32/7.3.0/include/c++/bits/basic_ios.h:37,
                 from D:/mingw-w64/i686-7.3.0-posix-dwarf-rt_v5-rev0/mingw32/lib
/gcc/i686-w64-mingw32/7.3.0/include/c++/ios:44,
                 from D:/mingw-w64/i686-7.3.0-posix-dwarf-rt_v5-rev0/mingw32/lib
/gcc/i686-w64-mingw32/7.3.0/include/c++/ostream:38,
                 from D:/mingw-w64/i686-7.3.0-posix-dwarf-rt_v5-rev0/mingw32/lib
/gcc/i686-w64-mingw32/7.3.0/include/c++/iostream:39,
                 from main.cpp:2:
D:/mingw-w64/i686-7.3.0-posix-dwarf-rt_v5-rev0/mingw32/lib/gcc/i686-w64-mingw32/
7.3.0/include/c++/bits/streambuf_iterator.h:369:5: note: candidate: template<cla
ss _CharT2> typename __gnu_cxx::__enable_if<std::__is_char<_CharT2>::__value, st
d::istreambuf_iterator<_CharT> >::__type std::find(std::istreambuf_iterator<_Cha
rT>, std::istreambuf_iterator<_CharT>, const _CharT2&)
     find(istreambuf_iterator<_CharT> __first,
     ^~~~
D:/mingw-w64/i686-7.3.0-posix-dwarf-rt_v5-rev0/mingw32/lib/gcc/i686-w64-mingw32/
7.3.0/include/c++/bits/streambuf_iterator.h:369:5: note:   template argument ded
uction/substitution failed:
main.cpp:75:52: note:   mismatched types 'std::istreambuf_iterator<_CharT>' and
'char*'
         auto it2 = std::find(ClientInput, it1, '\n');

komentarz 12 czerwca 2018 przez j23 Mędrzec (194,920 p.)

Załącz <algorithm>.

Podobne pytania

0 głosów
2 odpowiedzi 328 wizyt
pytanie zadane 19 maja 2018 w C i C++ przez Mamrotek Nowicjusz (180 p.)
+2 głosów
2 odpowiedzi 2,944 wizyt
pytanie zadane 26 kwietnia 2015 w C i C++ przez achilles147 Dyskutant (9,580 p.)
0 głosów
1 odpowiedź 553 wizyt
pytanie zadane 21 lutego 2018 w Offtop przez pionk18 Obywatel (1,590 p.)

92,555 zapytań

141,403 odpowiedzi

319,559 komentarzy

61,942 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...