从单个客户端多次接收我只能从客户端接收一次,然后每个响应都是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,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,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,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,0);

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

    // recieve server message
    char* server_verdict;
    recv(data_exchange_socket,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,0);
        printf("Server Message: %s\n",server_message);
    }
    close(data_exchange_socket);
    return 0;
}

我认为是因为也许我们只能用一个data_exchange_socket接收一次。但是后来我发现客户端代码不正确。

请告诉我以上内容是否正确。我不明白为什么它不起作用。

解决方法

您没有正确处理字符串传输。您不是通过发送字符串长度或使用空终止符来构造字符串,以便接收方知道何时停止读取每个字符串。而且,您没有为recv()分配任何要读取的内存。或者考虑到TCP是流的事实,因此send()recv()之间没有1:1的关系,因此可以进行部分发送/读取。

尝试更多类似方法:

常用:

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 == '\0') ? (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 != '\0');

    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,size_t size)
{
    char *pdata = data;
    int numRecv;

    while (size > 0)
    {
        numRecv = recv(sock,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,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] = '\0';
    *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,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;
}