在unix上发送带套接字的消息 - 奇怪的行为

时间:2016-05-16 12:43:45

标签: c sockets unix hash client-server

我正在学习unix套接字,我决定为本地通信编写一个简单的客户端/服务器程序。 它的工作原理如下:服务器创建一个套接字并开始监听,直到客户端连接,接收消息并简单地将其发送回客户端;另一方面,客户端连接到套接字,发送字符串消息,接收服务器响应并终止。

我成功实施了这样的程序。对于测试目的(我知道它没有意义,它只是一个测试),我想在消息的底部添加消息本身的哈希值。我使用了SHA256函数的OpenSSL实现,修改了如下行为:

  • 服务器创建一个套接字并开始监听;
  • 客户端连接到套接字,要求发送字符串,计算该字符串的散列,将其连接到原始消息(使用管道“|”作为分隔符)并将消息发送到服务器;
  • 服务器将消息拆分为纯文本和散列,计算普通部分的散列并使用接收的散列检查它
    • 如果匹配,则会在简单消息中添加内容
    • 如果不这样做,则会覆盖原始的简单消息
    • ...然后它计算新消息的哈希值,并将其发送到客户端
  • 客户端收到消息并以相同的方式检查哈希

现在,问题是我使用完全相同的函数来计算和验证散列,但是在服务器端我得到了一个哈希不匹配,而在客户端,一切都按预期工作。

我确定我做错了什么。

服务器输出:

Socket created
Bind done
Waiting for incoming connections...
Connection accepted
Message received
Message: hello
Hash not corresponding
Message sent

客户端输出:

Socket created
Connected
Enter message to send: hello
Message sent
Message received
Hashes match
Server reply: Hash mismatch

这是服务器代码:

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <openssl/sha.h>

int simpleSHA256(void *input, unsigned long length, unsigned char *md) {
    SHA256_CTX context;
    if(!SHA256_Init(&context))
        return 0;

    if(!SHA256_Update(&context, (unsigned char*)input, length))
        return 0;

    if(!SHA256_Final(md, &context))
        return 0;

    return 1;
}

int main(int argc, char *argv[]) {
    int socket_desc, client_sock, c;
    struct sockaddr_in server, client;
    char client_message[1000], client_plain_message[1000], server_message[1000], *received_client_message_hash;

    // Create socket
    socket_desc = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_desc == -1) {
        printf("Could not create socket\n");
        return 1;
    }
    printf("Socket created\n");

    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(8888);

    // Bind
    if (bind(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0) {
        perror("Bind failed. Error");
        close(socket_desc); close(client_sock); return 1;
    }
    printf("Bind done\n");

    // Start listening
    listen(socket_desc, 3);
    printf("Waiting for incoming connections...\n");

    c = sizeof(struct sockaddr_in);

    // Accept connection
    if ((client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) < 0) {
        perror("Accept failed");
        close(socket_desc); close(client_sock); return 1;
    }
    printf("Connection accepted\n");

    // Receive message from client
    if (recv(client_sock, client_message, 1000, 0) < 0 ) {
        perror("Receive failed");
        close(socket_desc); close(client_sock); return 1;
    }
    printf("Message received\n");

    strcpy(client_plain_message, client_message);
    strtok_r(client_plain_message, "|", &received_client_message_hash);

    // Verify hash
    unsigned char computed_client_message_hash[SHA256_DIGEST_LENGTH];

    if(!simpleSHA256(client_plain_message, strlen(client_plain_message), computed_client_message_hash)) {
        printf("Error computing hash\n");
        close(socket_desc); close(client_sock); return 1;
    }

    printf("Message: %s\n", client_plain_message);

    if (!strcmp(computed_client_message_hash, received_client_message_hash)) {
        printf("Hash not corresponding\n");

        strcpy(server_message, "Hash mismatch");
    } else {
        printf("Hashes match\n");

        strcpy(server_message, client_plain_message);
        strcat(server_message, "_added_text_");
    }

    // Compute new hash
    unsigned char message_hash[SHA256_DIGEST_LENGTH];

    if(!simpleSHA256(client_plain_message, strlen(client_plain_message), message_hash)) {
        printf("Error computing hash\n");
        close(socket_desc); close(client_sock); return 1;
    }

    // Concatenate new hash with response
    strcat(server_message, "|");
    strcat(server_message, message_hash);

    // Ansers to client
    if (write(client_sock, server_message, strlen(server_message)) < 0) {
        perror("Write failed");
        close(socket_desc); close(client_sock); return 1;
    }

    printf("Message sent\n");

    fflush(stdout);
    return 0;
}

这是客户端代码:

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <openssl/sha.h>

int simpleSHA256(void *input, unsigned long length, unsigned char *md) {
    SHA256_CTX context;
    if(!SHA256_Init(&context))
        return 0;

    if(!SHA256_Update(&context, (unsigned char*)input, length))
        return 0;

    if(!SHA256_Final(md, &context))
        return 0;

    return 1;
}

int main(int argc, char *argv[]) {
    int sock;
    struct sockaddr_in server;
    char client_message[1000], server_reply[1000], server_message[1000], *received_server_message_hash;

    // Create socket
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        printf("Could not create socket\n");
        close(sock); return 1;
    }
    printf("Socket created\n");

    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr("127.0.0.1"); // destination ip
    server.sin_port = htons(8888); // destination port

    // Connect to server
    if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0) {
        perror("Connect failed. Error\n");
        return 1;
    }
    printf("Connected\n");

    printf("Enter message to send: ");
    scanf("%s", client_message);

    // Compute hash
    unsigned char client_message_hash[SHA256_DIGEST_LENGTH];

    if(!SHA256(client_message, strlen(client_message), client_message_hash)) {
        printf("Error computing hash\n");
        close(sock); return 1;
    }

    // Concatenate hash with message
    strcat(client_message, "|");
    strcat(client_message, client_message_hash);

    // Send message
    if (write(sock, client_message, strlen(client_message)) < 0) {
        printf("Write failed\n");
        close(sock); return 1;
    }

    printf("Message sent\n");

    // Receive response
    if (recv(sock, server_reply, 1000, 0) < 0) {
        printf("Receive failed\n");
        close(sock); return 1;
    }
    printf("Message received\n");

    strcpy(server_message, server_reply);
    strtok_r(server_message, "|", &received_server_message_hash);

    // Verify hash
    unsigned char computed_server_message_hash[SHA256_DIGEST_LENGTH];

    if(!simpleSHA256(server_message, strlen(server_message), computed_server_message_hash)) {
        printf("Error computing hash\n");
        close(sock); return 1;
    }

    // Check if hashes match
    if (!strcmp(computed_server_message_hash, received_server_message_hash)) {
        printf("Hash not corresponding\n");
        close(sock); return 1;
    }
    printf("Hashes match\n");

    printf("Server reply: %s\n", server_message);

    // Close connection
    close(sock);
    return 0;
}

2 个答案:

答案 0 :(得分:2)

你是

  • 忽略recv()
  • 返回的长度
  • 假设单个读取足以接收整个消息
  • 假设邮件以空值终止。

检查你的假设。

答案 1 :(得分:-1)

我通过将strlen()替换为常量值来解决我的问题,正如alk所指出的那样。

注意:下面的代码只是一个测试,它并不意味着没有bug或完全可以用于任何目的。我将其发布为仅限于我遇到的问题的解决方案。

更新了客户端:

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <openssl/sha.h>

#define MAX_LENGTH 10000

int simpleSHA256(void *input, unsigned long length, unsigned char *md) {
    SHA256_CTX context;
    if(!SHA256_Init(&context))
        return 0;

    if(!SHA256_Update(&context, (unsigned char*)input, length))
        return 0;

    if(!SHA256_Final(md, &context))
        return 0;

    return 1;
}

int main(int argc, char *argv[]) {
    int sock;
    struct sockaddr_in server;
    char client_message[MAX_LENGTH], server_reply[MAX_LENGTH], server_message[MAX_LENGTH], *received_server_message_hash;

    // Create socket
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        printf("Could not create socket\n");
        close(sock); return 1;
    }
    printf("Socket created\n");

    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr("127.0.0.1"); // destination ip
    server.sin_port = htons(8888); // destination port

    // Connect to server
    if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0) {
        perror("Connect failed. Error\n");
        return 1;
    }
    printf("Connected\n");

    printf("Enter message to send: ");
    scanf("%s", client_message);

    // Compute hash
    unsigned char client_message_hash[SHA256_DIGEST_LENGTH];

    if(!SHA256(client_message, MAX_LENGTH, client_message_hash)) {
        printf("Error computing hash\n");
        close(sock); return 1;
    }

    // Concatenate hash with message
    strcat(client_message, "|");
    strcat(client_message, client_message_hash);

    // Send message
    if (write(sock, client_message, MAX_LENGTH) <= 0) {
        printf("Write failed\n");
        close(sock); return 1;
    }

    printf("Message sent\n");

    // Receive response
    if (recv(sock, server_reply, MAX_LENGTH, 0) <= 0) {
        perror("Receive failed");
        close(sock); return 1;
    }
    printf("Message received\n");

    strcpy(server_message, server_reply);
    strtok_r(server_message, "|", &received_server_message_hash);

    // Verify hash
    unsigned char computed_server_message_hash[SHA256_DIGEST_LENGTH];

    if(!simpleSHA256(server_message, MAX_LENGTH, computed_server_message_hash)) {
        printf("Error computing hash\n");
        close(sock); return 1;
    }

    // Check if hashes match
    if (!strcmp(computed_server_message_hash, received_server_message_hash)) {
        printf("Hash not corresponding\n");
        close(sock); return 1;
    }
    printf("Hashes match\n");

    printf("Server reply: %s\n", server_message);

    // Close connection
    fflush(stdout);
    close(sock);
    return 0;
}

更新了服务器:

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <openssl/sha.h>

#define MAX_LENGTH 10000

int simpleSHA256(void *input, unsigned long length, unsigned char *md) {
    SHA256_CTX context;
    if(!SHA256_Init(&context))
        return 0;

    if(!SHA256_Update(&context, (unsigned char*)input, length))
        return 0;

    if(!SHA256_Final(md, &context))
        return 0;

    return 1;
}

int main(int argc, char *argv[]) {
    int socket_desc, client_sock, c;
    struct sockaddr_in server, client;
    char client_message[MAX_LENGTH], client_plain_message[MAX_LENGTH], server_message[MAX_LENGTH], *received_client_message_hash;

    // Create socket
    socket_desc = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_desc == -1) {
        printf("Could not create socket\n");
        return 1;
    }
    printf("Socket created\n");

    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY; // accetto da qualsiasi indirizzo
    server.sin_port = htons(8888); // porta di ascolto

    // Bind
    if (bind(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0) {
        perror("Bind failed. Error");
        close(socket_desc); close(client_sock); return 1;
    }
    printf("Bind done\n");

    // Start listening
    listen(socket_desc, 3);
    printf("Waiting for incoming connections...\n");

    c = sizeof(struct sockaddr_in);

    // Accept connection
    if ((client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) < 0) {
        perror("Accept failed");
        close(socket_desc); close(client_sock); return 1;
    }
    printf("Connection accepted\n");

    // Receive message from client
    if (recv(client_sock, client_message, MAX_LENGTH, 0) <= 0 ) {
        perror("Receive failed");
        close(socket_desc); close(client_sock); return 1;
    }
    printf("Message received\n");

    strcpy(client_plain_message, client_message);
    strtok_r(client_plain_message, "|", &received_client_message_hash);

    printf("%i\n", strlen(client_plain_message));

    // Verify hash
    unsigned char computed_client_message_hash[SHA256_DIGEST_LENGTH];

    if(!simpleSHA256(client_plain_message, MAX_LENGTH, computed_client_message_hash)) {
        printf("Error computing hash\n");
        close(socket_desc); close(client_sock); return 1;
    }

    printf("Message: %s\n", client_plain_message);

    if (!strcmp(computed_client_message_hash, received_client_message_hash)) {
        printf("Hash not corresponding\n");

        strcpy(server_message, "Hash mismatch");
    } else {
        printf("Hashes match\n");

        strcpy(server_message, client_plain_message);
        strcat(server_message, "_added_text_");
    }

    // Compute new hash
    unsigned char message_hash[SHA256_DIGEST_LENGTH];

    if(!simpleSHA256(client_plain_message, MAX_LENGTH, message_hash)) {
        printf("Error computing hash\n");
        close(socket_desc); close(client_sock); return 1;
    }

    // Concatenate new hash with response
    strcat(server_message, "|");
    strcat(server_message, message_hash);

    // Ansers to client
    if (write(client_sock, server_message, MAX_LENGTH) <= 0) {
        perror("Write failed");
        close(socket_desc); close(client_sock); return 1;
    }

    printf("Message sent\n");

    fflush(stdout);
    close(socket_desc);
    close(client_sock);
    return 0;
}