TCP server message дополнительные символы c ++ - PullRequest
0 голосов
/ 12 ноября 2018

Я думаю, что что-то упустил и не имеет смысла.

Я пишу довольно простой TCP-сервер, все работает примерно так, как ожидалось, но когда сообщение «500 LOGIN FAILED» отправляется по сети, оно интерпретируется как «$ 500 LOGIN FAILED».

Я тестирую свой сервер, используя telnet на localhost

вот упрощенная версия моего кода

recv(c_sockfd, buf, BUFFSIZE, 0))
inBuffer.push_back(buf);
auto messageToSend = checkResponse(parseBuffer(inBuffer.back()));
//get the second thing in the tuple
outBuffer.push_back(std::get<1>(messageToSend));
bzero(buf, sizeof(buf));
send(c_sockfd, &outBuffer.back(), sizeof( outBuffer.back() ), 0)

В функции checkResponse я реализую логику, чтобы решить, какое сообщение отправлять, и каким-то образом, когда я отправляю сообщение об ошибке, в начале сообщения добавляется дополнительный символ.

ПРИМЕР 1:

Connected to localhost.
Escape character is '^]'.
200 LOGIN
Robot345\r\n
201 PASSWORD
674\r\n
202 OK
INFO iasdijasdjiajsdiajdijasidjiansdjsdvhdf dfvsdfsdf\r\n
&501 SYNTAX ERROR 

Обратите внимание на символ "&"

ПРИМЕР 2:

Connected to localhost.
Escape character is '^]'.
200 LOGIN
Robot345\r\n
201 PASSWORD
456\r\n
$500 LOGIN FAILED

Обратите внимание на символ "$"

Кто-нибудь знает, где можно добавить дополнительные символы в строку?

Я не хотел включать полный код, потому что требовалось, чтобы все было в одном файле, что затрудняет чтение. Вот и все.

ПОЛНЫЙ КОД:

#include <iostream>
#include <regex>
#include <iterator>
#include <vector>
#include <sstream>
#include <string>
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <tuple>

#define MIN_PORT 3000
#define MAX_PORT 3999
#define BUFFSIZE 1000
/**
 0 - LOGIN SUCCESSFUL, USERNAME IS IN THE BUFFER
 1 - PASSWORD CHECK
 2 - PASSWORD OK, COMMUNICATING
 */
int state = 0;
std::string username, password;
/**
 CHECKS ENTERED PASSWORD BASES ON THE SUM OF ASCII VALUES OF USERNAME
 @return: true on success, false otherwise
 */
bool checkPassword(std::string password){
    std::istringstream sst;
    sst.str(username);
    unsigned char byte = '\0';
    int value = 0;
//    std::cout << "byte poprve: " << byte << std::endl;
//    std::cout << "byte poprve INT: " << (int) byte << std::endl;

    while (sst >> byte) {
        std::cout << "podruhe: " << byte << std::endl;
        std::cout << "podruhe INT: " << (int) byte << std::endl;
        std::cout << "Prubezna SUMA: " << (int) value << std::endl;
        value += byte;
    }
    std::cout << "suma: " << value << std::endl;
    // Check the entered password
    if (password == std::to_string(value)) {
        return true;
    }

    return false;
}
/**
 CHECKS MESSAGE SYNTAX BASED ON THE STATE WE ARE IN
 CHECKS PASSWORD
 CHECKS CHECK SUM
 @param response <string type (if available), string message to parse>
 @return TRUE on success, FALSE otherwise
 */
bool checkMessage(std::tuple<std::string,std::string> response){

    auto messageToParse = std::get<1>(response);
    std::string delimeter = "\r\n";
    std::string::size_type pos = messageToParse.find(delimeter);
    //INITIAL CHECK
    if (pos < 1){
        return false;
    }
    //somehow you have to multiply the length by 2
    auto parsedMessage = messageToParse.substr(0,pos - 2*delimeter.length());
    std::cout << parsedMessage << " : THIS IS YOUR PARSED MESSAGE";

    //USERNAME
    if (state == 0) {
        username = parsedMessage;
        return true;
    }

    //PASSWORD CHECK
    if (state == 1 && checkPassword(parsedMessage)) {
        password = parsedMessage;
        return true;
    }

    if (state == 2) {
        std::string type = std::get<0>(response);

        //INFO
        if( type == "I" ){
            return true;
        }
        //PHOTO
        if ( type == "F") {
            return true;
        }

    }

    return false;
}
/**
 THIS FUNC WILL CHECK RESPONSE FROM THE ROBOT, AND DECIDE WHAT TO DO BASED ON THE STATE
 @return tuple<bool TRUE if everything is right,std::string MESSAGE to send to the robot>
 */
std::tuple<bool,std::string> checkResponse(std::tuple<std::string, std::string> response){

    if (state == 0) {
        if (checkMessage(response)) {
            std::cout << state << " / / state" << std::endl;
            return std::make_tuple(true, "201 PASSWORD\r\n");
        }
    }
    if (state == 1) {
        // TADY BUDE JESTE PODMINKA, ZE HESLO JE SPRAVNE
        if(checkMessage(response)){
            std::cout << state << " / / / state" << std::endl;
            return std::make_tuple(true, "202 OK\r\n");
        }else{
            std::cout << state << " / / / / state" << std::endl;
            return std::make_tuple(false, "500 LOGIN FAILED\r\n");
        }
    }
    if (state == 2) {

        if (checkMessage(response)) {
            std::cout << state << " / / / / / state" << std::endl;
            return std::make_tuple(true, "202 OK\r\n");
        }else{
            std::cout << state << " / / / / / / state" << std::endl;
            return std::make_tuple(false, "501 SYNTAX ERROR \r\n");
        }
    }
    std::cout << state << " / / / / / / / / state" << std::endl;
    return std::make_tuple(false, "unexpected result");
}
/**
 This func will parse the incoming buffer
 @param buffer incoming buffer
 @return tuple <String type of message (U,I,P,F),  String actual message>
 */
std::tuple<std::string, std::string> parseBuffer(std::string buffer){
    if (state == 0) {
        return std::make_tuple("U", buffer);
    }
    if (state == 1) {
        return std::make_tuple("P", buffer);
    }else{
        std::string delimeter = " ";
        std::string::size_type pos = buffer.find(delimeter);
        std::string type = buffer.substr(0, pos );
        std::string message = buffer.erase(0, pos + delimeter.length());

        return std::make_tuple(type, message);
    }


}


int main(int argc, char *argv[])
{
    char   buf[BUFFSIZE];
    std::vector<std::string> outBuffer;
    std::vector<std::string> inBuffer;
    int    sockfd, c_sockfd;
    sockaddr_in my_addr, rem_addr;
    socklen_t    rem_addr_length;
    int    mlen;
    const int PORT_NUM = atoi(argv[1]);

    if( (PORT_NUM > MAX_PORT) || (PORT_NUM < MIN_PORT)){
        perror("Port number is not acceptable");
         exit(-1);
    }

    if ((sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
    {
        perror("Socket nelze otevrit");
        exit(-1);
    }

    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(PORT_NUM);
    std::cout << PORT_NUM << " PORT NUM" << std::endl;
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr)) == -1)
    {
        perror("Chyba v bind");
        close(sockfd); exit(1);
    }

    if (listen(sockfd, SOMAXCONN) == -1)
    {
        perror("Nelze provest listen");
        close(sockfd); exit(1);
    }

    while (1)
    {
        rem_addr_length=sizeof(rem_addr);
        c_sockfd = accept(sockfd, (struct sockaddr*) &rem_addr, &rem_addr_length);
        if ( c_sockfd == -1)
        {
            perror("Nelze accept");
            close(sockfd); exit(1);
        }
        ///FIRST MESSAGE
        std::string ok = "200 LOGIN\r\n";
        send(c_sockfd, &ok, sizeof(std::string), 0);

        if ((mlen = recv(c_sockfd, buf, BUFFSIZE, 0)) == -1)
            perror("Chyba pri cteni");
        else{

            while (mlen)
            {

                ///---------- MAIN PART--------------
                //This is where comunication is happening
                inBuffer.push_back(buf);
                //Parse the buffer, check the message and
                auto messageToSend = checkResponse(parseBuffer(inBuffer.back()));
                //get the second thing in the tuple
                outBuffer.push_back(std::get<1>(messageToSend));
                bzero(buf, sizeof(buf));
                ///---------- MAIN PART--------------
                state++;
                std::cout << state << " state num" << std::endl;
                if (send(c_sockfd, &outBuffer.back(), sizeof( outBuffer.back() ), 0) == -1)
                {
                    perror("Chyba pri zapisu");
                    break;
                }else{

                }

                std::cout << inBuffer.back() << std::endl;

                if ((mlen = recv(c_sockfd, buf, BUFFSIZE, 0)) == -1)
                {
                    perror("Chyba pri cteni");
                    break;
                }
            }

            close(c_sockfd);

            }
    }
}

1 Ответ

0 голосов
/ 12 ноября 2018

Проблема с этим:

std::vector<std::string> outBuffer;

и это:

send(c_sockfd, &outBuffer.back(), sizeof( outBuffer.back() ), 0)

Вы не можете отправлять std::string объекты по сети. Вы должны отправить строку, которая содержит . Это две совершенно разные вещи.

Для простого исправления, например,

send(c_sockfd, outBuffer.back().c_str(), outBuffer.back().length(), 0)

Если вы хотите отправить завершающий ноль, добавьте его к длине для отправки.


Для получения более подробной информации, в то время как реализации std::string позволяют оптимизировать небольшие строки, которые будут содержаться внутри фактического объекта, в противном случае объект std::string на самом деле является не чем иным, как размером и указателем на фактическую строку (реализации могут есть и другие участники).

Указатель является уникальным для текущего запущенного процесса в хост-системе. Вы не можете передать указатель по сети. Вы даже не можете сохранить указатель на файл, а затем загрузить его снова и заставить его работать в новом процессе (даже если это процесс из той же программы).

Отправляя объект std::string, все, что вы действительно отправляете, это этот указатель. Так что на стороне получателя он понятия не имеет, что вы на самом деле отправляете и как это следует обрабатывать.

...