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

Send message with sockets on unix - weird behaviour

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

我成功实施了这样的程序。出于 测试 目的(我知道这没有意义,这只是一个测试),我想在消息底部添加消息本身的散列。我使用 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;
}

你是

  • 忽略 recv()
  • 返回的长度
  • 假设一次读取就足以接收整条消息
  • 假设消息以 null 结尾。

检查你的假设。

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

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

更新客户端:

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