Я думаю, что что-то упустил и не имеет смысла.
Я пишу довольно простой 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);
}
}
}