jungyh0218 jungyh0218 - 1 month ago 10
C Question

Implementing Stop and wait with C & UDP, and what does cause 'resource temporarily unavailable'?

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.)

Answer

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.