从单个客户端接收多次。我只能从客户端接收一次,然后每个响应都是 NULL

Receiving multiple times from a single client. I can only recieve from the client once and then every response is NULL

我希望服务器向客户端发送一个 OTP(一次性密码)。然后客户端将密码发送回服务器,如果它们匹配则进行进一步的对话。

此代码用于服务器端:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>


int main(int argc, char* argv[])
{
    // Create a listen socket
    int listen_socket = socket(PF_INET, SOCK_STREAM, 0);

    // Create Local Server address and initialise family, port number, IP address
    struct sockaddr_in server_address;
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(10000);
    server_address.sin_addr.s_addr = INADDR_ANY;

    // bind listen socket with local server address
    bind(listen_socket, (struct sockaddr*)&server_address, sizeof(struct sockaddr_in));

    // listen for a connection
    listen(listen_socket, 10);

    // accept a connection to create socket for data exchange
    int data_exchange_socket = accept(listen_socket, NULL, NULL);

    //--------------------------------- LOGIC ----------------------------------------
    //OTP for authentication
    char* server_password = "vikas@hplap";

    // send OTP to client
    send(data_exchange_socket, server_password, strlen(server_password), 0);

    // recieve OTP
    char* client_password;
    recv(data_exchange_socket, client_password, 50, 0);

    // authenticate
    if(strcmp(server_password, client_password) == 0)
    {
        // Correct OTP sent by client
        char* server_verdict = "Correct";
        send(data_exchange_socket, server_verdict, strlen(server_verdict), 0);

        // get client message
        char* client_message;
        recv(data_exchange_socket, client_message, 50, 0);
        printf("Client Message: %s\n", client_message);

        //server respond with hello
        char* server_response = "Hello, Press any key to exit...";
        send(data_exchange_socket, server_response, strlen(server_response), 0);
        printf("Data sent\n"); // This doesn't execute
    }
    else
    {
        // handle wrong OTP by client
        char* server_response = "Incorrect OTP entered!";
        send(data_exchange_socket, server_response, strlen(server_response), 0);
    }

    // shut down server
    printf("Server Closed :)\n"); // This is also not executed
    close(listen_socket);
    return 0;
}

这是客户端的代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h> 
#include <string.h>


int main(int argc, char* argv[])
{
    // create socket for data exchange
    int data_exchange_socket = socket(PF_INET, SOCK_STREAM, 0);

    // create remote server address
    struct sockaddr_in server_address;
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(10000);
    server_address.sin_addr.s_addr = INADDR_ANY;

    // try to connect with server
    int status=connect(data_exchange_socket, (struct sockaddr *)&server_address, sizeof(struct sockaddr_in));
    if(status==-1)
    {
        printf("\n connection error.....");
    }

    // recieve OTP from server
    char* otp;
    recv(data_exchange_socket, otp, 50, 0);

    // send server the otp recieved
    send(data_exchange_socket, otp, strlen(otp), 0);

    // recieve server message
    char* server_verdict;
    recv(data_exchange_socket, server_verdict, 50, 0);


    if(strcmp(server_verdict, "Correct") == 0)
    {
        // Send "Hi" to server
        char* client_response = "Hi";
        send(data_exchange_socket, client_response, strlen(client_response), 0);

        // recieve server message
        char* server_message;
        recv(data_exchange_socket, server_message, 50, 0);
        printf("Server Message: %s\n", server_message);
    }
    close(data_exchange_socket);
    return 0;
}

我想是因为一个data_exchange_socket可能我们只能收到一次。但是后来我发现客户端代码不是这样。

请告诉我以上是否属实。我不明白为什么它不起作用。

您没有正确处理您的字符串传输。您不是通过发送字符串长度或空终止符以这种方式构建字符串,以便接收方可以知道何时停止读取每个字符串。而且您没有为 recv() 分配任何内存来读取。或者考虑到 TCP 是一个流,所以 send()recv() 之间没有 1:1 关系,部分 sends/reads 是可能的。

尝试更像这样的东西:

常见:

int sendString(int sock, const char *str)
{
    size_t len = strlen(str) + 1;
    int numSent;

    while (len > 0)
    {
        numSent = send(sock, str, len, 0);
        if (numSent < 0)
            return -1;
        str += numSent;
        len -= numSent;
    }

    return 0;
}

int recvString(int sock, char **msg)
{
    size_t len = 0, cap = 0, size;
    char ch, *newmsg;
    int numRecv;

    *msg = NULL;

    do
    {
        numRecv = recv(sock, &ch, 1, 0);
        if (numRecv <= 0)
        {
            free(*msg);
            *msg = NULL;
            return numRecv;
        }

        if (len == cap)
        {
            size = (ch == '[=10=]') ? (len + 1) : (len + 50);

            newmsg = realloc(*msg, size);
            if (newmsg == NULL)
            {
                free(*msg);
                *msg = NULL;
                return -1;
            }

            memcpy(newmsg, *msg, len);
            *msg = newmsg;
            cap = size;
        }

        (*msg)[len] = ch;
        ++len;
    }
    while (ch != '[=10=]');

    return 1;
}

或者:

int sendRaw(int sock, void *data, size_t size)
{
    char *pdata = data;
    int numSent;

    while (size > 0)
    {
        numSent = send(sock, pdata, size, 0);
        if (numSent < 0)
            return -1;
        pdata += numSent;
        size -= numSent;
    }

    return 0;
}

int recvRaw(int sock, void *data, size_t size)
{
    char *pdata = data;
    int numRecv;

    while (size > 0)
    {
        numRecv = recv(sock, pdata, size, 0);
        if (numRecv <= 0)
            return numRecv;
        pdata += numRecv;
        size -= numRecv;
    }

    return 1;
}

int sendUInt32(int sock, uint32_t val)
{
    val = htonl(val);
    return sendRaw(sock, &val, sizeof(val));
}

int recvUInt32(int sock, uint32_t *val)
{
    int res = recvRaw(sock, val, sizeof(*val));
    if (res <= 0) return res;
    *val = ntohl(*val);
    return 1;
}

int sendString(int sock, const char *str)
{
    size_t len = strlen(str);
    if (sendUInt32(sock, len) < 0) return -1;
    return sendRaw(sock, str, len);
}

int recvString(int sock, char **msg)
{
    *msg = NULL;

    uint32_t len;
    int res = recvUInt32(sock, &len);
    if (res <= 0)
        return res;

    char *newmsg = malloc(len + 1);
    if (newmsg == NULL)
        return -1;

    res = recvRaw(sock, newmsg, len);
    if (res <= 0)
    {
        free(newmsg);
        return res;
    }

    newmsg[len] = '[=11=]';
    *msg = newmsg;

    return 1;
}

那么你可以这样做:

服务器:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

#include "Common.h"

int main(int argc, char* argv[])
{
    // Create a listen socket
    int listen_socket = socket(PF_INET, SOCK_STREAM, 0);
    if (listen_socket < 0)
    {
        perror("Error creating listening socket");
        return -1;
    }

    // Create Local Server address and initialize family, port number, IP address
    struct sockaddr_in server_address;
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(10000);
    server_address.sin_addr.s_addr = INADDR_ANY;

    // bind listen socket with local server address
    if (bind(listen_socket, (struct sockaddr*)&server_address, sizeof(struct sockaddr_in)) < 0)
    {
        perror("Error binding listening socket");
        close(listen_socket);
        return -1;
    }

    // listen for a connection
    if (listen(listen_socket, 10) < 0)
    {
        perror("Error opening listening socket");
        close(listen_socket);
        return -1;
    }

    // accept a connection to create socket for data exchange
    int data_exchange_socket = accept(listen_socket, NULL, NULL);
    if (data_exchange_socket < 0)
    {
        perror("Error accepting a client");
        close(listen_socket);
        return -1;
    }

    //--------------------------------- LOGIC ----------------------------------------
    //OTP for authentication

    // send OTP to client
    if (sendString(data_exchange_socket, "vikas@hplap") < 0)
    {
        perror("Error sending password to client");
        close(data_exchange_socket);
        close(listen_socket);
        return 0;
    }

    // receive OTP
    char* client_password;
    int res = recvString(data_exchange_socket, &client_password);
    if (res <= 0)
    {
        if (res < 0)
            perror("Error receiving password from client");
        else
            printf("Disconnected while receiving password from client\n");
        close(data_exchange_socket);
        close(listen_socket);
        return 0;
    }

    // authenticate
    int res = strcmp(server_password, client_password);
    free(client_password);
    if (res == 0)
    {
        // Correct OTP sent by client
        if (sendString(data_exchange_socket, "Correct") < 0)
        {
            perror("Error sending verdict to client");
            close(data_exchange_socket);
            close(listen_socket);
            return 0;
        }

        // get client message
        char* client_message;
        res = recvString(data_exchange_socket, &client_message);
        if (res <= 0)
        {
            if (res < 0)
                perror("Error receiving message from client");
            else
                printf("Disconnected while receiving message from client\n");
            close(data_exchange_socket);
            close(listen_socket);
            return 0;
        }

        printf("Client Message: %s\n", client_message);
        free(client_message);

        //server respond with hello
        if (sendString(data_exchange_socket, "Hello, Press any key to exit...") < 0)
        {
            perror("Error sending message to client");
            close(data_exchange_socket);
            close(listen_socket);
            return 0;
        }

        printf("Data sent\n"); // This doesn't execute
    }
    else
    {
        // handle wrong OTP by client
        if (sendString(data_exchange_socket, "Incorrect OTP entered!") < 0)
        {
            perror("Error sending verdict to client");
            close(data_exchange_socket);
            close(listen_socket);
            return 0;
        }
    }

    // shut down server
    printf("Server Closed :)\n"); // This is also not executed

    close(data_exchange_socket);
    close(listen_socket);
    return 0;
}

客户:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h> 
#include <string.h>

#include "Common.h"

int main(int argc, char* argv[])
{
    // create socket for data exchange
    int data_exchange_socket = socket(PF_INET, SOCK_STREAM, 0);
    if (data_exchange_socket < 0)
    {
        perror("Error creating socket");
        return -1;
    }

    // create remote server address
    struct sockaddr_in server_address;
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(10000);
    server_address.sin_addr.s_addr = inet_addr("127.0.0.1");

    // try to connect with server
    if (connect(data_exchange_socket, (struct sockaddr *)&server_address, sizeof(struct sockaddr_in)) < 0)
    {
        perror("Error connecting to server");
        close(data_exchange_socket);
        return -1;
    }

    // recieve OTP from server
    char* otp;
    int res = recvString(data_exchange_socket, &otp);
    if (res <= 0)
    {
        if (res < 0)
            perror("Error receiving password from server");
        else
            printf("Disconnected while receiving password from server\n");
        close(data_exchange_socket);
        return -1;
    }

    // send server the otp received
    if (sendString(data_exchange_socket, otp) < 0)
    {
        perror("Error sending password to server");
        free(otp);
        close(data_exchange_socket);
        return -1;
    }
    free(otp);

    // receive server message
    char* server_verdict;
    res = recvString(data_exchange_socket, &server_verdict);
    if (res <= 0)
    {
        if (res < 0)
            perror("Error receiving verdict from server");
        else
            printf("Disconnected while receiving verdict from server\n");
        close(data_exchange_socket);
        return -1;
    }

    res = strcmp(server_verdict, "Correct");
    free(server_verdict);
    if (res == 0)
    {
        // Send "Hi" to server
        if (sendString(data_exchange_socket, "Hi") < 0)
        {
            perror("Error sending message to server");
            close(data_exchange_socket);
            return -1;
        }

        // recieve server message
        char* server_message;
        res = recvString(data_exchange_socket, &server_message);
        if (res <= 0)
        {
            if (res < 0)
                perror("Error receiving message from server");
            else
                printf("Disconnected while receiving message from server\n");
            close(data_exchange_socket);
            return -1;
        }

        printf("Server Message: %s\n", server_message);
        free(server_message);
    }

    close(data_exchange_socket);
    return 0;
}