2

I am implementing stop&wait with c and udp socket programming. To simulate this protocol, I wrote two codes.

This is my server.c file:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>


typedef struct packet{
    char data[1024];
}Packet;

typedef struct frame{
    int frame_kind; //ACK:0, SEQ:1 FIN:2
    int sq_no;
    int ack;
    Packet packet;
}Frame;

int main(int argc, char** argv)
{
    int sockfd;
    int clilen;
    int state;
    int n;
    int sum;
    int recv_result;

    int frame_id = 0;

    Packet packet;
    Frame frame;
    Frame recv_frame;
    char buffer[1024] = "";

    struct timeval tv;

    struct sockaddr_in serveraddr, clientaddr;

    FILE* infile = fopen(argv[2], "r");
    if(argc != 3)
    {
        perror("error! usage: $./server <PORT> filename\n");
        exit(1);
    }
    if(infile == NULL)
    {
        printf("error! failed to open the file.\n");
        exit(0);
    }

    clilen = sizeof(clientaddr);
    sockfd = socket(AF_INET, SOCK_DGRAM, 0); //using diagram instead of stream-- UDP
    if(sockfd < 0)
    {
        perror("socket error: ");
        exit(0);
    }

    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serveraddr.sin_port = htons(atoi(argv[1])); //set port number 9999

    //set socket option -- timeout is 100000 microseconds

    tv.tv_sec = 1;
    tv.tv_usec = 0;
    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(struct timeval));

    state = bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
    if(state == -1)
    {
        perror("bind error: ");
        exit(0);
    }

    do{
        n = fscanf(infile, "%s", buffer);

        strcpy(packet.data, buffer);
        memcpy(&(frame.packet), &packet, sizeof(Packet));
        frame.frame_kind = 1; //SEQ
        frame.sq_no = frame_id;
        frame.ack = 0;
        printf("flag2");
        while(1)
        {
            sendto(sockfd, &frame, sizeof(frame), 0, (struct sockaddr*)&clientaddr, (socklen_t)clilen);
            printf("Frame %d sent\n", frame_id);
            recv_result = recvfrom(sockfd, &recv_frame, sizeof(recv_frame), 0,(struct sockaddr*)&clientaddr, &clilen );

            if(recv_result > 0 && recv_frame.sq_no == 0 && recv_frame.ack == frame_id){
                printf("Ack %d received\n", recv_frame.sq_no);
                break;
            }else{
                printf("Frame %d time expired\n", frame_id);
            }
        }
        frame_id++;
    }while(n > 0);

    printf("finished\n");
    return 0;
}

This is my client.c file:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

typedef struct packet{
    char data[1024];
}Packet;

typedef struct frame{
    int frame_kind; //ACK:0, SEQ:1 FIN:2
    int sq_no;
    int ack;
    Packet packet;
}Frame;

int main(int argc, char *argv[])
{
    int sock;
    int str_len;
    socklen_t adr_sz;
    FILE* outfile = fopen("output.txt", "w");
    struct sockaddr_in serv_adr, from_adr;
    Frame ackframe, recv_frame;
    int frame_id;
    int recv_result;
    struct timeval tv;

    if(argc!=3){
        printf("Usage : %s <IP> <port>\n", argv[0]);
        exit(1);
    }
    sock=socket(PF_INET, SOCK_DGRAM, 0);   
    if(sock==-1)
    {
        printf("error! failed to open the socket\n");
        exit(1);
    }

    memset(&serv_adr, 0, sizeof(serv_adr));
    adr_sz = sizeof(serv_adr);
    serv_adr.sin_family=AF_INET;
    serv_adr.sin_addr.s_addr=inet_addr(argv[1]);
    serv_adr.sin_port=htons(atoi(argv[2]));

    tv.tv_sec = 1;
    tv.tv_usec = 0;
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(struct timeval));

    frame_id = 0;
    while(1)
    {
        recv_result = recvfrom(sock, &recv_frame, sizeof(recv_frame), 0,(struct sockaddr*)&serv_adr, &adr_sz);
        perror("error: ");
        printf("data %s\n", recv_frame.packet.data);
        printf("recv result %d\n", recv_result);
        printf("recv frame=%d, frame_kind = %d\n", recv_frame.sq_no, recv_frame.frame_kind);
        if(recv_result > 0 && recv_frame.frame_kind == 1 && recv_frame.sq_no==frame_id){
            printf("Frame %d received\n", recv_frame.sq_no);
            fprintf(outfile, "%s", recv_frame.packet.data);
            ackframe.frame_kind = 0;
            ackframe.ack = recv_frame.sq_no + 1;
            printf("Ack %d sent\n", ackframe.ack);
            sendto(sock, &recv_frame, sizeof(recv_frame), 0,(struct sockaddr*)&serv_adr, adr_sz);


            break;
        }else{
            printf("Frame %d time expired\n", frame_id);
        }
    }   
    close(sock);
    fclose(outfile);
    return 0;
}

The server needs 3 arguments: ./server <port> <test.txt>

The client needs also 3 arguments: ./client <ip> <port>

It is executed, but recvfrom of client always returns -1.

I read some questions with same topic, but could not find out the error from my code. Is there any way to fix my code with recvfrom & sendto? Or do I need to use select function? (I will only communicate with one server & one client.)

jungyh0218
  • 558
  • 1
  • 4
  • 17
  • You *do* realize that `fread()` doesn't null-terminate what it reads? – EOF Oct 15 '15 at 06:49
  • Oh I fixed it in my newest code, but did not fix the one of this code. But I don't think it is the reason of 'resource temporarily unavailable' error. – jungyh0218 Oct 15 '15 at 06:52
  • Given that you `strcpy()` something that is possibly not null-terminated, and right afterwards you `memcpy()` that same content, I am not inclined to debug this code for you. – EOF Oct 15 '15 at 06:55
  • If a system-call like [`recvfrom`](http://man7.org/linux/man-pages/man2/recvfrom.2.html) return `-1` then you can (and should) check [`errno`](http://man7.org/linux/man-pages/man3/errno.3.html) to see what went wrong. Also, the value of `errno` is *undefined* if the previous function didn't actually failed, never check `errno` unless the previous function actually failed. – Some programmer dude Oct 15 '15 at 07:01
  • The result of perror is "Resource temporarily Unavailable". I read another question and according to it, it is because there is no data to read from the socket. I wonder is there any solution to solve this problem with using recvfrom function. – jungyh0218 Oct 15 '15 at 07:02
  • Also, this error has a name EAGAIN. – jungyh0218 Oct 15 '15 at 07:03
  • 1
    You get that error because you might have set a to low timeout. If there's nothing to receive then the `recvfrom` function will timeout and return that error. As for *why* there's nothing received is a different story altogether, and there may be a hundred different reasons for it, but after a quick glance at your code it seems that your programs are a little off, I'll explain more in an answer. – Some programmer dude Oct 15 '15 at 07:07
  • @jungyh0218 Could you provide the working code in the answer. I am facing the same issue and not able to resolve it. – I am learning Jun 17 '21 at 07:09
  • @Someprogrammerdude could you provide the working code in the answer. I am facing the same issue and not able to resolve it. – I am learning Jun 17 '21 at 07:10

1 Answers1

1

The "client" and "server" program contains some dubious code. First lets take the "server", which calls sendto with clientaddr which you haven't initialized. Who knows where you try to send the packets. This, in fact, leads to undefined behavior, as the contents of the structure is indeterminate.

Then lets take the client, in which you call recvfrom on a socket that isn't bound locally. The address structure pointer you pass to recvfrom is filled in by the recvfrom function, but the data in it is not used in any other way.

There are probably other problems, but these two stand out.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • I fixed it. The cause was initialization. :) – jungyh0218 Oct 15 '15 at 13:50
  • 1
    @jungyh0218 please add working code in the answer I am facing the same issue. I am a beginner – I am learning Jun 17 '21 at 07:11
  • @Iamlearning If you look at the server code in the question, you see that the OP is initializing the structure `serveraddr`, but not the structure `clientaddr`. You must initialize the address structure with the address you want to send the packet to. – Some programmer dude Jun 17 '21 at 07:15