【问题标题】:Send message with sockets on unix - weird behaviour在 unix 上使用套接字发送消息 - 奇怪的行为
【发布时间】:2016-09-12 06:14:34
【问题描述】:

我正在学习 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;
}

【问题讨论】:

  • 不好int c; ... accept(..., (socklen_t*)&amp;c)
  • 他们说strlen() 和网络代码不能放在一起...... ;-)
  • 好点,谢谢。我通过将strlen() 替换为常量值解决了我的特定问题。

标签: c sockets unix hash client-server


【解决方案1】:

你是

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

检查你的假设。

【讨论】:

  • 我找到了一个仅限于我正在做的小测试的解决方案,但是您的提示很宝贵。谢谢。
【解决方案2】:

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

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

更新客户端:

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

【讨论】:

  • 通过使用strcpy() 并忽略recv() 返回的实际计数,您仍然承认导致strlen() 不正确的相同谬误。
猜你喜欢
  • 1970-01-01
  • 2022-01-16
  • 2015-05-17
  • 2019-09-06
  • 2012-11-08
  • 1970-01-01
  • 2015-03-01
  • 1970-01-01
  • 2012-12-13
相关资源
最近更新 更多