Сервер не получает то, что я посылаю по TCP

0

В настоящее время я пишу серверное приложение client- для iOS. Клиент - Objective-C/CocoaTouch, а серверный сервер написан на C++. Прямо сейчас я борюсь с TCP-связью - для отправки конкретной информации на сервер.

Каждая другая передача/прием пакетов работает, но для этого пакета сервер, похоже, получает "плохие" данные. И сервер, и клиент немного ориентированы, поэтому утверждение не является проблемой.

Здесь код отправителя:

- (void) sendGameUpdateWithFile:(NSString*)filePath gameID:(NSInteger)gameID {
    NSMutableData* data = [[NSMutableData alloc] init];
    data = [NSMutableData dataWithContentsOfFile:filePath];

    fileheadPacket head;

    head.msgtype = 0x12;
    strncpy(head.data1, [myUsername cStringUsingEncoding:NSUTF8StringEncoding], [myUsername length]);
    head.data1[[myUsername length]] = '\0';
    int followingPackets = 1;
    if([data length] % 1024 == 0){
        if([data length] > 1024){
            followingPackets = (int)[data length]/1024;
        }
    } else {
        followingPackets = (int)([data length]/1024)+1;
    }
    head.following = followingPackets;
    head.fileid = (int)gameID;
    head.size = sizeof(fileheadPacket);

    [mySock writeData:[NSData dataWithBytes:&head length:sizeof(fileheadPacket)] withTimeout:-1 tag:8];

    NSRange thisRange;
    thisRange.length = 1024;

    for(int i = 0; i < followingPackets; i++){
        thisRange.location = i*1024;

        if(thisRange.location + thisRange.length > [data length]){
            thisRange.length = [data length] - thisRange.location;
        }

        filePacket tmp;
        tmp.extra = (int)thisRange.length;
        tmp.msgtype = 0x13;
        tmp.size = sizeof(filePacket);
        tmp.following = (int)gameID;
        [data getBytes:tmp.fileBuffer range:thisRange];

        [mySock writeData:[NSData dataWithBytes:&tmp length:sizeof(filePacket)] withTimeout:-1 tag:8];

        NSLog(@"Wrote packet of type 0x%02x, size %d", tmp.msgtype, tmp.size);
    }
}

Простите беспорядок этого кода, он все еще находится в раннем развитии и будет улучшен.

Здесь код приемника:

std::vector<filePacket> PacketInterpreter::readPacket(filePacket* inPacket, int FD){
    //The returned vector contains stuff to return to the socket. If it empty, there nothing to return (and thus, the client on that FD shouldn't be listening)

    packetsToSend.clear();
    packetsToSend.reserve(1024);

    std::cout << "Received a packet of type " << inPacket->msgtype << " with size " << inPacket->size << std::endl;

    switch (inPacket->msgtype){
        case 0x12:
        {
            fileheadPacket* ptr = (fileheadPacket*) inPacket;
            assembleFile(ptr->following, ptr->fileid);
            break;
        }
        case 0x13:
            concatFilePart(inPacket->extra, inPacket->following, inPacket->fileBuffer);
            break;
    }

    return packetsToSend;

}

void PacketInterpreter::assembleFile(int following, int gameID){
    std::cout << "assembleFile with following: " << following << " and gameid " << gameID << std::endl;
    char* s = (char*)malloc(sizeof(char)*(following+1)*1024);
    inAssembly.insert(std::make_pair(gameID, s));
    inAssemblyCountdown.insert(std::make_pair(gameID, following+1));
    inAssemblyCountup.insert(std::make_pair(gameID, 0));
}

void PacketInterpreter::concatFilePart(int readLen, int gameID, unsigned char* data){

    for(int i = 0; i < readLen; i++){
        inAssembly[gameID][inAssemblyCountup[gameID]] = data[i];
        inAssemblyCountup[gameID]++;
    }

    inAssemblyCountdown[gameID]--;
    if(readLen != 1024 || inAssemblyCountdown[gameID] == 0){
        makeFile(gameID, inAssembly[gameID]);
        delete inAssembly[gameID];
        inAssembly.erase(gameID);
        inAssemblyCountdown.erase(gameID);

    }
}

void PacketInterpreter::makeFile(int gameID, char* buffer){
    std::string rmgameIDdir = ("rm -r " + std::to_string(gameID));
    system(rmgameIDdir.c_str());
    std::string gameIDdir = "mkdir " + std::to_string(gameID);
    std::string constructedPath = std::to_string(gameID);
    constructedPath += "/";

    std::system(gameIDdir.c_str());
    std::cout << gameIDdir.c_str() << std::endl;

    std::ofstream thisFile;
    thisFile.open(constructedPath+"sound.caf");

    std::cout << "opened " << constructedPath+"sound.caf" << " is open? " << thisFile.is_open() << std::endl;


    std::string temp = "";
    for(int i = 0; i < inAssemblyCountup[gameID]; i++){
        thisFile << std::hex << buffer[i];
    }
    thisFile.close();

    std::cout << "File assembled at " << constructedPath << "sound.caf" << std::endl;
}

void PacketInterpreter::assembleFile(int following, int gameID){
    std::cout << "assembleFile with following: " << following << " and gameid " << gameID << std::endl;
    char* s = (char*)malloc(sizeof(char)*(following+1)*1024);
    inAssembly.insert(std::make_pair(gameID, s));
    inAssemblyCountdown.insert(std::make_pair(gameID, following+1));
    inAssemblyCountup.insert(std::make_pair(gameID, 0));
}

void PacketInterpreter::concatFilePart(int readLen, int gameID, unsigned char* data){

    for(int i = 0; i < readLen; i++){
        inAssembly[gameID][inAssemblyCountup[gameID]] = data[i];
        inAssemblyCountup[gameID]++;
    }

    inAssemblyCountdown[gameID]--;
    if(readLen != 1024 || inAssemblyCountdown[gameID] == 0){
        makeFile(gameID, inAssembly[gameID]);
        delete inAssembly[gameID];
        inAssembly.erase(gameID);
        inAssemblyCountdown.erase(gameID);

    }
}

Структуры, которые я использую по обе стороны соединения, выглядят следующим образом:

//Packet used for small stuff
typedef struct small_packet {
    int msgtype;
    int size;
    int extra;
    int following;
    char data1[64];
    char data2[64];
} packet;

//Packet used for files
typedef struct file_packet {
    int msgtype; //For partial file packet this should be 0x02
    int size;
    int extra;
    int following;
    char data1[64];
    unsigned char fileBuffer[1024];
} filePacket;

//Used for file headers
typedef struct filehead_packet {
    int msgtype;
    int size;
    int extra;
    int following;
    char data1[64];
    int fileid;
    char rest[60];
} fileheadPacket;

Я точно знаю, что структуры упакованы одинаково на обоих устройствах, потому что все остальные сообщения используют одни и те же пакеты, и они работают так, как должны. Когда я пытаюсь отправить файл с сервера client->, это типичный журнал:

Received a packet of type 18 with size 144
assembleFile with following: 367 and gameid 109
Received a packet of type 19 with size 1104
Received a packet of type 19 with size 1104
Received a packet of type 19 with size 1104
Received a packet of type 19 with size 1104
Checking for new games
Received a packet of type 0 with size 0
Received a packet of type -262149 with size -196612
Received a packet of type -131075 with size -196612
Received a packet of type -1 with size -1
Received a packet of type 327685 with size 327685
Received a packet of type 131074 with size 196611
Received a packet of type 65537 with size 65537
Received a packet of type -65538 with size -65538
Received a packet of type 131074 with size 196611
Received a packet of type 196611 with size 65537
Received a packet of type 131074 with size 196611
Received a packet of type 393222 with size 196611
Received a packet of type 0 with size 0
... many packets which make no sense, although the total number of packets is correct (367 in this case) ...
Received a packet of type -196612 with size -196612
Received a packet of type 131074 with size 131074
Received a packet of type 65537 with size 131074
Received a packet of type -196612 with size -196612
Received a packet of type 0 with size 65537
Received a packet of type -393223 with size -327686
Received a packet of type 131074 with size 131074
Received a packet of type 393222 with size 393222
Received a packet of type 0 with size 0
Received a packet of type 19 with size 1104
Received a packet of type 19 with size 1104
Received a packet of type 19 with size 1104
mkdir 109
opened 109/sound.caf is open? 1
File assembled at 109/sound.caf

Это просто сводит меня с ума, потому что я понятия не имею, что случилось. Дайте мне знать, если вам нужно больше образцов кода (например, select() -block в main(), который отправляет и принимает пакеты. Любая помощь очень ценится. Спасибо заранее!

  • 0
    На всякий случай, если вы пишете & s, sizeof (s) структурирует непосредственно к проводу, обратите внимание, что расположение и размер их могут быть не одинаковыми на обоих концах, а также порядком байтов.
  • 0
    Как я отмечаю в своем вопросе, порядковый номер обоих концов одинаков, а упаковка одинакова (я проверил ASM, созданный компиляторами на обоих концах, и они совпадают).
Теги:
sockets
tcp

1 ответ

-3

Я действительно узнал, что здесь не так. Сервер читает быстрее, чем iPhone отправляет свои пакеты, что означает, что только первая половина или около того пакетов, переданных с iPhone, достигла конца строки на сервере filedescriptor, когда сервер пытается прочитать полный размер (filePacket).

Так как обе машины мало ориентированы, "хвост" пакета считывается сначала сервером, и в этом случае метаинформация, содержащаяся в каждом пакете, сохраняется "в конце" данных, доступных в настоящее время в файловом дескрипторе. Когда мы пытаемся читать 1140 байт и говорим только о том, что половина его фактически наступила, метаданные получают случайные значения из поля fileBuffer пакета.

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

Итак, что я узнал сегодня? Не отправляйте слишком большие пакеты по TCP и ожидайте, что сервер прочитает все это в одном фрагменте. 1K слишком много, чтобы отправить сразу.

  • 4
    Я думаю, вы должны были узнать больше, чем это. Правильное решение - сидеть в цикле и ждать, пока вы не получите все, что ожидаете (который может быть фиксированного размера или передаваться как часть заголовка). Это стандартная практика. Ваше исправление также сломано.
  • 1
    И я буду понижать это, чтобы другие не копировали ваш «ответ».
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню