2017-02-15 25 views
0

我正在使用多線程服務器/客戶端。我遇到的問題是服務器處理有時看起來有點不同。發回的消息總是正確的,但服務器打印的消息有點奇怪。如果它是一個像「你好」這樣的簡短字,那麼一切正常。如果是長字或有空間,如「Binominalkoeffizient」失印serversided消息字符串是:意外的多線程服務器反應 - C

Binomina 
lkoeffiz 
ient 
fiz 

任何想法,我的錯誤是什麼?

PS:當我使用telnet時,服務器反應是一樣的!

服務器主營:

#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; 

} 

服務器的文件

#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插座性質。

顧名思義,流套接字是字節流;他們不保留消息邊界,以便通過一次呼叫recv收到一個與send的呼叫一起發送的內容。單個send可能會被分成多個recv調用,或者多個send調用可能會合併成一個單獨的recv或兩者。它們確保順序,因爲字節將按照它們發送的相同順序接收。

您需要實現自己的記錄標記,可能需要插入\0字符來分隔單詞,或者使用長度前綴。

+0

好吧!非常感謝你!我會嘗試使用\ 0 – Josey

+0

@Josey考慮接受這個答案來創建這樣的記錄標記,如果它最有幫助的話。 –

+0

非常感謝! – Josey

0

這是正常行爲。當您使用send時,您不知道將發送多少個字節。可能會發生所有的單詞,字符都被髮送。但是有辦法解決這個問題。一種方法是給你發送的字符串寫一個簡單的頭文件,其中包含你發送的字符串的長度。所以你知道字符串何時結束。例如,您可以使用線程持續查看消息,並且由於頭部包含字符串的長度,因此您知道何時打印\ n。send的行爲不能更改,因爲它是內核,就是這樣做的。

+0

也謝謝!真的有幫助! – Josey

0

除了什麼其他的答案已經說:

你的代碼,明確要求在每次讀取8個字節。 recvmessage是一個指針,並且指針在系統上是8個字節,所以sizeof(recvmessage)是8.