c++ клиент-сервер

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by 0o Chris o0, 25 Oct 2012.

  1. 0o Chris o0

    0o Chris o0 New Member

    Joined:
    16 Oct 2011
    Messages:
    142
    Likes Received:
    1
    Reputations:
    0
    Немного исправил код, теперь данные всегда доходят, но ответ все равно неполный.
    Вот, собственно, код сервера:
    Code:
    #include <iostream>
    #include <winsock.h>
    using namespace std;
    
    SOCKET serv;
    SOCKET ClientSock;
    
    int main()
    {
        try {
            WSADATA wsa;
            if(WSAStartup(MAKEWORD(2,0), &wsa)) throw "Can't start WSA";
    
            serv = socket(AF_INET, SOCK_STREAM, 0);
            if(serv == INVALID_SOCKET) throw "INVALID SOCKET serv";
    
            struct sockaddr_in srv;
    
            srv.sin_addr.s_addr = INADDR_ANY;
            srv.sin_port = htons(4356);
            srv.sin_family = AF_INET;
            memset(&(srv.sin_zero), 0, 8);
    
    
    
            if(bind(serv, (sockaddr *)&srv, sizeof(srv))) throw "Can't bind socket";
    
            if(listen(serv, 10)) throw "Can't listen socket";
    
    
            struct sockaddr_in client_addr;
            memset(&(client_addr.sin_zero), 0, 8);
    
            char response[256];
            char* answer = new char[256];
            answer = "HelloFromServer";
            int clientLen = sizeof(client_addr);
            if(ClientSock = accept(serv, (struct sockaddr *)&client_addr, &clientLen)) {
                cout << "New Client " << inet_ntoa(client_addr.sin_addr) <<endl;
            while (recv(ClientSock, response, sizeof(response)-1, 0)) {
    
                if(send(ClientSock, answer, sizeof(answer), 0) == SOCKET_ERROR) throw "Can't send data";
                cout << response << endl;
            }
    
            delete(answer);
            closesocket(serv);
            closesocket(ClientSock);
            WSACleanup();
    
        }
    }
    
        catch (const char* b) {
            closesocket(serv);
            closesocket(ClientSock);
            WSACleanup();
            MessageBox(NULL, b, "Error", MB_OK);
        }
    
        return 0;
    }
    
    А тут код клиента:
    Code:
    #include <iostream>
    #include <winsock.h>
    using namespace std;
    
    SOCKET sock;
    
    int main()
    {
     try {
        WSAData wsa;
        if(WSAStartup(MAKEWORD(2,0), &wsa)) throw "Can't start WSA";
    
    
        sock = socket(AF_INET, SOCK_STREAM, 0);
        if(sock == INVALID_SOCKET) throw "INVALID SOCKET sock";
    
        struct sockaddr_in addr;
    
        addr.sin_family = AF_INET;
        addr.sin_port = htons(4356);
        memset(&(addr.sin_zero), 0, 8);
        addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    
        char data[256];
        char *response = new char[256];
    
        if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) throw "Can't connect to server";
    
        std::string checkEx;
        while(1) {
            cin >> data;
            checkEx = data;
            if(checkEx == "exit") throw "Exit";
            if(send(sock, data, sizeof(data), 0) == SOCKET_ERROR) throw "Can't send data";
            if(recv(sock, response, sizeof(response)-1, 0) == SOCKET_ERROR) throw "Can't recieve data";
            cout << response << endl;
        }
        closesocket(sock);
        WSACleanup();
     }
     catch (const char* b) {
         closesocket(sock);
         WSACleanup();
        MessageBox(NULL, b, "Error", MB_OK);
     }
        return 0;
    }
    
    Проблема в том, что до сервера доходят данные только в первый раз. Клиенту же вместо "HellowFromServer" приходит "Hel". Больше данные до сервера не доходят.
     
    #1 0o Chris o0, 25 Oct 2012
    Last edited: 25 Oct 2012
  2. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    936
    Likes Received:
    162
    Reputations:
    27
    Code:
    if(recv(sock, response, sizeof(response)-1, 0) == SOCKET_ERROR) throw "Can't recieve data";
    Здесь ты пытаешься получить 3 байта данных от сервера. sizeof(response) возвращает размер типа char *, который равняется 4 и также ты еще отнимаешь 1. Вместо sizeof() используй strlen() из string.h.
     
    #2 Chrome~, 25 Oct 2012
    Last edited: 25 Oct 2012
    1 person likes this.
  3. 0o Chris o0

    0o Chris o0 New Member

    Joined:
    16 Oct 2011
    Messages:
    142
    Likes Received:
    1
    Reputations:
    0
    Спасибо. Не стал strlen использовать, в сервере создал другую переменную char buf[256], в нее копирую, потом отправляю.
     
  4. Chrome~

    Chrome~ Elder - Старейшина

    Joined:
    13 Dec 2008
    Messages:
    936
    Likes Received:
    162
    Reputations:
    27
    Да, нормально. Также немного поспешил, когда сказал, что в recv нужно использовать strlen() (она же возвратит не обязательно полный размер массива, а скорее даже наоборот). Лучше использовать константное значение для размера буфера, чтобы избавиться от "магических" чисел.
     
  5. alexey-m

    alexey-m Elder - Старейшина

    Joined:
    15 Jul 2009
    Messages:
    518
    Likes Received:
    100
    Reputations:
    37
    читаем доки там все написано как, чего и в каком виде
     
  6. 0o Chris o0

    0o Chris o0 New Member

    Joined:
    16 Oct 2011
    Messages:
    142
    Likes Received:
    1
    Reputations:
    0
    Я по этой статье разбирался, довольно хорошо все описано
    http://www.insidepro.com/kk/006/006r.shtml
     
  7. 0o Chris o0

    0o Chris o0 New Member

    Joined:
    16 Oct 2011
    Messages:
    142
    Likes Received:
    1
    Reputations:
    0
    Теперь имеется возможность передачи файла, и каждый клиент обрабатывается в новом потоке, но почему то при подключении второго клиента, первому так и не приходит ответ от сервера.
    Сервер:
    Code:
    #include <iostream>
    #include <winsock.h>
    #include <windows.h>
    #include <fstream>
    using namespace std;
    
    DWORD WINAPI New_Client(LPVOID clien_socket);
    SOCKET serv;
    SOCKET ClientSock;
    
    int main()
    {
        try {
            WSADATA wsa;
            if(WSAStartup(MAKEWORD(2,0), &wsa)) throw "Can't start WSA";
    
            serv = socket(AF_INET, SOCK_STREAM, 0);
            if(serv == INVALID_SOCKET) throw "INVALID SOCKET serv";
    
            struct sockaddr_in srv;
    
            srv.sin_addr.s_addr = INADDR_ANY;
            srv.sin_port = htons(4356);
            srv.sin_family = AF_INET;
            memset(&(srv.sin_zero), 0, 8);
    
    
    
            if(bind(serv, (sockaddr *)&srv, sizeof(srv))) throw "Can't bind socket";
    
            if(listen(serv, 10)) throw "Can't listen socket";
    
    
            struct sockaddr_in client_addr;
            memset(&(client_addr.sin_zero), 0, 8);
    
    
            int clientLen = sizeof(client_addr);
    
                while (ClientSock = accept(serv, (struct sockaddr *)&client_addr, &clientLen)) {
                    cout << "New Client " << inet_ntoa(client_addr.sin_addr) <<endl;
                    DWORD thID;
                    CreateThread(NULL, NULL, New_Client, &ClientSock, NULL, &thID);
                }
           closesocket(serv);
           closesocket(ClientSock);
           WSACleanup();
    
            return 0;
    }
    
        catch (const char* b) {
            closesocket(serv);
            closesocket(ClientSock);
            WSACleanup();
            MessageBox(NULL, b, "Server Error", MB_OK);
        }
    
        return 0;
    }
    
    DWORD WINAPI New_Client(LPVOID client_socket) {
        SOCKET my_sock = ((SOCKET *)client_socket)[0];
    
        char response[256];
        char BufForFile[1024];
        FILE* f;
        std::string DataType;
    
        while(recv(my_sock, response, sizeof(response), 0)) {
            DataType = response;
            if(DataType == "FILE") {
                recv(my_sock, response, sizeof(response), 0);
                f = fopen(response, "w");
                fclose(f);
                cout << "Recieving file " << response << endl;
                recv(my_sock, BufForFile, sizeof(BufForFile), 0);
                cout <<"Getting File : " << BufForFile << endl;
                std::ofstream ss;
                ss.open(response);
                ss << BufForFile;
                cout << "File getting success" << endl;
            }
            else if(DataType == "stop") {
                closesocket(my_sock);
                return 0;
            }
            else {
                if(send(ClientSock, response, sizeof(response), 0) == SOCKET_ERROR) throw "Can't send data";
                cout << response << endl;
            }
        }
        return 0;
    }
    
    Клиент:
    Code:
    #include <iostream>
    #include <winsock.h>
    #include <fstream>
    using namespace std;
    
    SOCKET sock;
    
    void sendFile(char* fname) {
        char buf[1024];
        FILE* f = fopen(fname, "r");
        fread(buf, 1024, 1, f);
        cout << "Send file : " << buf << endl;
        fclose(f);
        char file[256] = "FILE";
        char name[32];
        strcpy(name, fname);
        send(sock, file, sizeof(file), 0);
        send(sock, name, sizeof(name), 0);
        send(sock, buf, sizeof(buf), 0);
        cout << "File Send Successfully" << endl;
    }
    
    int main()
    {
     try {
        WSAData wsa;
        if(WSAStartup(MAKEWORD(2,0), &wsa)) throw "Can't start WSA";
    
    
        sock = socket(AF_INET, SOCK_STREAM, 0);
        if(sock == INVALID_SOCKET) throw "INVALID SOCKET sock";
    
        struct sockaddr_in addr;
    
        addr.sin_family = AF_INET;
        addr.sin_port = htons(4356);
        memset(&(addr.sin_zero), 0, 8);
        char* ip = new char[8];
        cout << "IP : ";
        cin >> ip;
        addr.sin_addr.s_addr = inet_addr(ip);
    
        char data[256];
        char response[256];
    
        if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) throw "Can't connect to server";
    
        std::string checkEx;
        char* fname = new char[32];
        while(1) {
            cin.getline(data, 256);
            checkEx = data;
            if(checkEx == "exit") throw "Exit";
            if(checkEx == "file") {
                cout << "Name : ";
                cin.getline(fname, 32);
                cout << "Trying to send file..." << endl;
                sendFile(fname);
                continue;
            }
            if(send(sock, data, sizeof(data), 0) == SOCKET_ERROR) throw "Can't send data";
            if(recv(sock, response, sizeof(response), 0) == SOCKET_ERROR) throw "Can't recieve data";
            cout << response << endl;
        }
        closesocket(sock);
        WSACleanup();
        
    catch (const char* b) {
                closesocket(sock);
                WSACleanup();
                MessageBox(NULL, b, "Server Error", MB_OK);
        }
        return 0;
    }
    
     }
    
     
    #7 0o Chris o0, 26 Oct 2012
    Last edited: 27 Oct 2012
  8. alexey-m

    alexey-m Elder - Старейшина

    Joined:
    15 Jul 2009
    Messages:
    518
    Likes Received:
    100
    Reputations:
    37
    1) в коде сервера:
    Code:
    ...
    else {
        if(send(ClientSock /* my_sock */, response, sizeof(response), 0) == SOCKET_ERROR)
    ...
    
    2) не везде проверяешь успешность отправки\приемки, не проверяешь сколь отправил и сколь принял байт, а только чекаешь на SOCKET_ERROR, чего не всегда достаточно, либо и того не делаешь
    3) учитывай фрагментацию пакетов
     
    1 person likes this.
  9. 0o Chris o0

    0o Chris o0 New Member

    Joined:
    16 Oct 2011
    Messages:
    142
    Likes Received:
    1
    Reputations:
    0
    Спасибо большое. Сколько раз ловил себя на том, что очень невнимателен...
     
    #9 0o Chris o0, 29 Oct 2012
    Last edited: 29 Oct 2012