2017-02-15 16 views
0

Я работаю над многопоточным сервером/клиентом. Проблема у меня в том, что обработка сервера иногда выглядит несколько разнообразнее. Сообщение, которое отправляется обратно, всегда корректно, но сообщение, которое распечатывает сервер, немного странно. Если это короткое слово, например «привет», все работает. Если это длинное слово или есть пробелы в строке, как «Binominalkoeffizient» выездном отпечатанных serversided сообщение является:неожиданная реакция многопоточного сервера - C

Binomina 
lkoeffiz 
ient 
fiz 

Любая идея, где моя ошибка есть?

PS: Реакция сервера такая же, когда я использую telnet!

сервера Main:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <unistd.h> 
#include <pthread.h> 

#include "server.h" 

int main(int argc, const char * argv[]) { 

    int sock; 
    struct sockaddr_in server; 

    sock = socket(AF_INET, SOCK_STREAM, 0); 
    socketStatusCheck(sock); 

    puts("[*] Starting Server ..."); 
    puts("[*] Initialize Server ..."); 
    initializeServer(&server, 8888); 
    bindServerToAddress(sock, server); 

    puts("[*] Waiting for incomming connections ... "); 
    puts(""); 
    listen(sock, 3); 

    connectionSwitch(sock); 

    close(sock); 

    return 0; 

} 

Сервер-File

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <unistd.h> 
#include <pthread.h> 

#include "server.h" 


void socketStatusCheck(int sock) { 
    if (sock == -1) { 
     perror("Error creating the socket: "); 
     exit(0); 
    } 
} 

void initializeServer(struct sockaddr_in *server, int port) { 
    server->sin_family = AF_INET; 
    server->sin_addr.s_addr = INADDR_ANY; 
    server->sin_port = htons(port); 
} 

void bindServerToAddress(int sock, struct sockaddr_in server) { 
    if (bind(sock, (struct sockaddr*) &server, sizeof(server)) < 0) { 
     perror("Error binding port: "); 
    } 
} 

void connectionSwitch(int sock) { 

    int nsock, lenbuf; 
    struct sockaddr_in client; 
    pthread_t pid = NULL; 

    lenbuf = sizeof(struct sockaddr_in); 
    while ((nsock = accept(sock, (struct sockaddr*) &client, (socklen_t*) &lenbuf))) { 
     puts("Client connected!"); 
     if (pthread_create(&pid, NULL, connectionHandler, (void*) &nsock)) 
      perror("Error creating thread: "); 
    } 
    if (nsock < 0) { 
     perror("Error accepting incomming client: "); 
    } 

    pthread_exit(pid); 

} 

void *connectionHandler(void *sockptr) { 

    int sock = *(int*) sockptr; 
    long isConnected; 
    char *smessage, *recvmessage; 

    smessage = "Hello! I am the server you just connected! \n"; 
    write(sock, smessage, strlen(smessage)); 

    recvmessage = malloc(5000 * sizeof(char)); // while ((isConnected = recv(sock, recvmessage, sizeof(recvmessage), 0)) > 0) 
    while ((isConnected = recv(sock, recvmessage, sizeof(recvmessage), 0)) > 0) { 
     //write(sock, recvmessage, sizeof(recvmessage)); 
     send(sock, recvmessage, sizeof(recvmessage), 0); 
     puts(recvmessage); 
    } 

    if (isConnected == 0) { 
     perror("Client disconnected: "); 
     fflush(stdout); 
    } 

    free(recvmessage); recvmessage = NULL; 

    return 0; 

} 
+0

'free (recvmessage); recvmessage = NULL; 'бессмысленно, удалить второй оператор. –

+0

Ну, это потому, что вы читаете только 8 байт за раз ('sizeof (recvmessage)' равно 8), и вы печатаете новую строку после каждой группы из 8 байтов, которые вы читаете. – immibis

ответ

3

Это действительно не имеет ничего общего с многопоточности, и все, что связано с природой SOCK_STREAM сокетов.

Потоковые сокеты, как следует из названия, представляют собой поток байтов; они не сохраняют границы сообщений, так что то, что отправляется с одним вызовом send, принимается одним звонком до recv. Один может быть разбит на несколько вызовов recv, или несколько вызовов send могут быть объединены в один recv или оба. Они гарантируют заказ, так как байты будут получены в том же порядке, в котором они отправлены.

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

+0

Хорошо! Большое спасибо! Я попытаюсь создать такую ​​запись с использованием \ 0 – Josey

+0

@ Josey подумайте о принятии этого ответа, если это вам больше всего поможет. –

+0

Большое спасибо! – Josey

0

Это нормальное поведение. Когда вы используете send, вы не знаете, сколько байтов будет отправлено. Может случиться, что все слова, символы отправлены. Однако есть способы решить эту проблему. Один из способов - написать простой заголовок для отправляемой строки, которая содержит длину строки, которую вы отправляете. Значит, вы знаете, когда строка заканчивается. Например, вы можете использовать поток для непрерывного просмотра сообщений и потому, что заголовок содержит длину строки, которую вы знаете, когда печатаете \ n. Поведение send не может быть изменено, потому что это ядро, которое делает это ,

+0

Спасибо тоже! Действительно полезно! – Josey

0

В дополнение к тому, что говорят другие ответы уже:

Ваш код специально просит, чтобы читать 8 байт за один раз. recvmessage - указатель, а указатели - 8 байтов в вашей системе, поэтому sizeof(recvmessage) - 8.