意外的多线程服务器反应 - C.

时间:2017-02-15 22:13:35

标签: c multithreading sockets

我正在使用多线程服务器/客户端。我遇到的问题是服务器处理有时看起来有点不同。发回的消息总是正确的,但服务器打印出来的消息有点奇怪。如果它是一个简短的词,比如"你好"一切正常。如果它是一个长字或字符串中有空格,如" Binominalkoeffizient" out-printed serversided消息是:

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;

}

3 个答案:

答案 0 :(得分:3)

这与多线程无关,而且与Ambiguous column name 'Id'.套接字的性质有关。

如图所示,流套接字是一个字节流;它们不保留消息边界,以便通过一次调用SOCK_STREAM接收一次调用send时发送的内容。单个recv可以在多个send来电中分解,或者多个recv来电可以合并为一个send,或两者兼而有之。它们确实保证了顺序,因为字节将按照它们发送的相同顺序接收。

您需要实现自己的记录标记,可能是通过插入recv个字符来分隔单词,或者使用长度前缀。

答案 1 :(得分:0)

这是正常行为。当您使用send时,您不知道将发送多少字节。可能会发生所有单词,字符都被发送。但是有办法解决这个问题。一种方法是将一个简单的标题写入您发送的字符串,其中包含您要发送的字符串的长度。所以你知道字符串何时结束。例如,您可以使用线程持续查找消息,因为标题包含您知道何时打印\ n的字符串长度。send的行为无法更改,因为它是内核,就是这样做。

答案 2 :(得分:0)

除了其他答案已经说明的内容之外:

您的代码特别要求一次读取8个字节。 recvmessage是一个指针,系统上的指针是8个字节,因此sizeof(recvmessage)为8。