简体   繁体   中英

C-language written UDP client doesn't receive a packet

Good day! I am writing a client-server program on C. I can't handle with the problem: Client send a message to server, he gets it and everything is OK, but when Server send a message to the Client, it doesn't catch a UDP-packet. Server finishes successfully, while Client keeps waiting for a message and doesn't get it. Here is the code.

udpClient.c:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdlib.h>

#define BUF_SIZE 1024
#define BAD_EXIT_STATUS 1

void throw(int code, char * message) {
    printf("%s\n", message);
    exit(code);
}

char * readline(FILE * input) {
    int size = 64;
    char * line = malloc(size * sizeof(char));
    char currentString[64];

    while (1) {
        fgets(currentString, sizeof(currentString), input);

        if (strstr(currentString, "\n")) {
            strcat(line, currentString);
            break;
        } else {
            size += 64;
            line = realloc(line, size * sizeof(char));
            strcat(line, currentString);
        }
    }
    return line;
}

typedef struct Args {
    char* IP;       // -a IP
    int port;       // -p port
} Args;

Args get_args(int argc, char **argv) {
    Args args;
    char * addr;
    char * port;
    if ((addr = getenv("L2ADDR"))) {
        args.IP = addr;
    } else {
        args.IP = "127.0.0.1";
    }
    if ((port = getenv("L2PORT"))) {
        args.port = atoi(port);
    } else {
        args.port = 1234;
    }

    int opt;
    while((opt = getopt(argc, argv, "a:p:vh")) != -1) {
        switch(opt) {
            case 'a':
                args.IP = optarg;
                break;
            case 'p':
                args.port = atoi(optarg);
                break;
            case 'v':
                printf("Lab2Server beta v.0.1.0\n");
                exit(0);
            case 'h':
                printf("You can use: \n"
                       "\t-a [string] -- Sets ip address;\n"
                       "\t-p [string] -- Sets port;\n"
                       "\t-v -- Shows a version.\n");
                exit(0);
            default:
                throw(BAD_EXIT_STATUS, "Use key -h to get some help.\n");
        }
    }

    return args;
}


int main(int argc, char **argv){
    Args args = get_args(argc, argv);

    char c;
    bool a = true;

    int sockfd;
    struct sockaddr_in serverAddr;

    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        throw(BAD_EXIT_STATUS, "Socket creation failed");
    }


    memset(&serverAddr, 0, sizeof(serverAddr));

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(args.port);
    serverAddr.sin_addr.s_addr = inet_addr(args.IP);
    char buffer[BUF_SIZE];
        printf("[Client]: ");
        char *request = readline(stdin);
        int n;
        socklen_t len;

        sendto(sockfd, (const char *) request, strlen(request), 0, (const struct sockaddr*)&serverAddr, sizeof(serverAddr));
        printf("[+]Data Send: %s", buffer);
        n = recvfrom(sockfd, (char *) buffer, BUF_SIZE, 0, (struct sockaddr *) &serverAddr, &len);
        printf("[Server]: %s", buffer);
    close(sockfd);
    return 0;

}

udpServer.c:

#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <math.h>
#include "utils.h"

#define BUF_SIZE 1024
#define ERROR_N_IS_BIG 1
#define ERROR_T_LESS_THAN_F 2
#define ERROR_N_IS_0 3
#define ERROR_NOT_ENOUGH_NUMBERS 4


int ds_size;
double *ds;

char *createResponse(char *buffer) {
    return buffer;
}

int main(int argc, char **argv){

    Args args = get_args(argc, argv); //прием аргов
    FILE *output = fopen(args.logFile, "w+"); // запись логов

    int sockfd; //для сокета
    struct sockaddr_in serveraddr, cliaddr; //сокеты сервера и клиента
    bool a = true;

    //обработка ошибки создания сокета
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        throw(BAD_EXIT_STATUS, "Socket creation failed");
    }


    memset(&serveraddr, 0, sizeof(serveraddr)); //выделение памяти под СС
    memset(&cliaddr, 0, sizeof(cliaddr)); // память под СК

    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(args.port);
    serveraddr.sin_addr.s_addr = inet_addr(args.IP);

    if (bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0) {
        throw(BAD_EXIT_STATUS, "Bind failed");
    }

    if (args.isDaemon) {
        pid_t process_id = 0;

        process_id = fork();
        if (process_id < 0) {
            throw(BAD_EXIT_STATUS, "Fork failed!\n");
        }
        if (process_id > 0) {
            printf("Server started with pid %d\n", process_id);
            exit(0);
        }

        umask(0);
        chdir("/");
        if (setsid() < 0) {
            throw(BAD_EXIT_STATUS, "Error on setsid()");
        }

        close(STDIN_FILENO);
        close(STDOUT_FILENO);
        close(STDERR_FILENO);
    }
    int n;
    socklen_t len;
    char buffer[BUF_SIZE];
    n = recvfrom(sockfd, (char *)buffer, BUF_SIZE, MSG_WAITALL, (struct sockaddr*)& cliaddr, &len);
    printf("[+]Data Received: %s", buffer);
    char *hello = "Hello from server";
    sendto(sockfd, (const char *) hello, strlen(hello), 0, (const struct sockaddr*)&cliaddr, sizeof(cliaddr));
    printf("Hello message sent.\n");


    return 0;

}

I also used next files to make the program run with keys

Utils.c

#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "utils.h"

void throw(int code, char * message) {
    printf("%s\n", message);
    exit(code);
}

Args get_args(int argc, char **argv) {
    Args args;
    char * wait;
    char * addr;
    char * port;
    char * logfile;
    if ((wait = getenv("L2WAIT"))) {
        args.waitFor = atoi(wait);
    } else {
        args.waitFor = 0;
    }
    if ((addr = getenv("L2ADDR"))) {
        args.IP = addr;
    } else {
        args.IP = "127.0.0.1";
    }
    if ((port = getenv("L2PORT"))) {
        args.port = atoi(port);
    } else {
        args.port = 1234;
    }
    if ((logfile = getenv("L2LOGFILE"))) {
        args.logFile = logfile;
    } else {
        args.logFile = "/tmp/lab2.log";
    }
    args.isDaemon = false;

    int opt;
    while((opt = getopt(argc, argv, "w:dl:a:p:vh")) != -1) {
        switch(opt) {
            case 'w':
                args.waitFor = atoi(optarg);
                break;
            case 'd':
                args.isDaemon = true;
                break;
            case 'l':
                args.logFile = optarg;
                break;
            case 'a':
                args.IP = optarg;
                break;
            case 'p':
                args.port = atoi(optarg);
                break;
            case 'v':
                printf("Lab2Server beta v.0.1.0\n");
                exit(0);
            case 'h':
                printf("You can use: \n"
                   "\t-w [int] -- Sets the delay;\n"
                   "\t-d -- Starts as daemon;\n"
                   "\t-a [string] -- Sets ip address;\n"
                   "\t-p [string] -- Sets port;\n"
                   "\t-l [string] -- Sets log file;\n"
                   "\t-v -- Shows a version.\n");
                exit(0);
            default:
                throw(BAD_EXIT_STATUS, "Use key -h to get some help.\n");
        }
    }

    return args;
}

double random_double(double min, double max) {
    return (double)rand() / RAND_MAX * (max - min) + min;
}

void logMessage(FILE * output, struct sockaddr_in client_addr, char * message) {
    time_t t = time(NULL);
    char * ip = inet_ntoa(client_addr.sin_addr);
    struct tm tm = *localtime(&t);
    fprintf(output, "[%d-%02d-%02d %02d:%02d:%02d | %s]: %s", tm.tm_year + 1900, tm.tm_mon + 1,
            tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, ip, message);
    fflush(output);
}

Utils.h

#include <netinet/in.h>

#ifndef UTILS_H
#define UTILS_H

#define BAD_EXIT_STATUS 1

typedef struct Args {
    int waitFor;    // -w N
    bool isDaemon;  // -d
    char* logFile;  // -l path
    char* IP;       // -a IP
    int port;       // -p port
} Args;

Args get_args(int, char**);

void throw(int, char*);

double random_double(double, double);

void logMessage(FILE *, struct sockaddr_in, char *);

#endif

These programs are compiled using the Make-file:

.PHONY: build clean

udpServer: udpServer.o utils.o
    gcc -o udpServer udpServer.o utils.o -lm

udpClient: udpClient.o
    gcc -o udpClient udpClient.o

udpServer.o: udpServer.c
    gcc -c -o udpServer.o udpServer.c -lm

udpClient.o: udpClient.c
    gcc -c -o udpClient.o udpClient.c

utils.o: utils.c
    gcc -c -o utils.o utils.c

clean:
    rm -rf *.o

build:
    make udpServer
    make udpClient
    make clean

So when you finished files, you need to run make build to make a program compiled an then you run a server with a command ./udpServer -a 127.0.0.1 -p 1234 (after "-a" you can post any IP-addr you want and after "-p" you post any port you want) and in a new window you run a Client with a command ./udpClient -a 127.0.0.1 -p 1234 (after "-a" you can post any IP-addr you want and after "-p" you post any port you want)

Please, help me with this problem.... I'm here to answer all your questions about my program. Thank you very much for help!

In file udpServer.c , function sendto() uses invalid cliaddr . To get right value, we initialize len before calling recvfrom() .

socklen_t len = sizeof(struct sockaddr);
recvfrom(sockfd, (char *)buffer, BUF_SIZE, MSG_WAITALL, (struct sockaddr*)& cliaddr, &len);

Manual of recvfrom recommends that

The argument addrlen is a value-result argument, which the caller should initialize before the call to the size of the buffer associated with src_addr and modified on return to indicate the actual size of the source address.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM