I'm having difficulties with this project. Everything's working except for binary files, probably because they're pretty big and would expect timeouts. The packetErrorSends are similar to send but they randomly drop packets. I only put them in the client side to isolate my problem. The algorithm I'm going for is send a piece of the file, if it receives it, send an 's' and continue reading and send the send piece. If it times out, send an 'e' and then hop in the loop, resend the current piece and recv the next status update. "While" checks the status, decides whether to move on or resend that piece. The problem is when is times out, server gets stuck in that loop resending the last chunk of data and client keeps timing out and sending back 'e's (the purpose of the print statements) Any clue what's happening?
client:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "packetErrorSend.h"
#include <sys/time.h>
ssize_t recvx(int sockfd, void *buf, size_t len) {
int var = recv(sockfd, buf, len, 0);
if(var != -1)
{
return var;
} else {
printf("%s \n","Did not receive.");
exit(1);
}
}
int main(int argc, char *argv[])
{
char buf[MAX_PACKET_DATA_SIZE];
struct addrinfo hints;
struct addrinfo *rp, *result;
int bytes_received = 1;
int s;
char *server;
char *port;
char *file;
int fd = -1; //file descriptor
int bytes_written = 1;
fd_set readfds;
struct timeval tv;
int rv = 0;
int status;
char sendStatus[1];
if (argc==4)
{
server = argv[1];
port = argv[2];
file = argv[3];
}
else
{
fprintf(stderr, "invalid # of arguments\n");
exit(1);
}
/* Translate host name into peer's IP address */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
hints.ai_protocol = 0;
if ((s = getaddrinfo(server, port, &hints, &result)) != 0 )
{
fprintf(stderr, "%s: getaddrinfo: %s\n", argv[0], gai_strerror(s));
exit(1);
}
/* Iterate through the address list and try to connect */
for (rp = result; rp != NULL; rp = rp->ai_next)
{
if ((s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1 )
{
continue;
}
if (connect(s, rp->ai_addr, rp->ai_addrlen) != -1)
{
break;
}
close(s);
}
if (rp == NULL)
{
perror("stream-talk-client: connect");
exit(1);
}
freeaddrinfo(result);
FD_ZERO(&readfds);
FD_SET(s, &readfds);
packetErrorSend(s, file, strlen(file)+1, 0);
tv.tv_sec = 2;
rv = select(s+1, &readfds, NULL, NULL, &tv);
if (rv == -1) {
perror("select"); // error occurred in select()
} else if (rv == 0) {
printf("Timeout occurred on filename! No data after 2 seconds.\n");
close(s);
exit(0);
} else {
status = recvx(s,buf,1);
}
if(status == 0 || buf[0] == 'e')
{
fprintf(stderr, "Server Error: unable to access file %s \n", file);
close(s);
exit(0);
}
if(buf[0] == 's')
{
fd =open(file, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if(fd == -1)
{
fprintf(stderr,"%s \n","Client Error: Open failed");
close(s);
exit(0);
}
FD_ZERO(&readfds);
FD_SET(s, &readfds);
bytes_received = MAX_PACKET_DATA_SIZE;
// while(bytes_received >= MAX_PACKET_DATA_SIZE)
while(bytes_received > 0)
{
tv.tv_sec = 3;
rv = select(s+1, &readfds, NULL, NULL, &tv);
if (rv == -1) {
perror("select");
} else if (rv == 0) {
printf("bytes_received in timeout %d \n", bytes_received );
printf("Timeout occurred! No data after 3 seconds.\n");
sendStatus[0] = 'e';
send(s,sendStatus,1,0);
} else {
bytes_received = recvx(s, buf, MAX_PACKET_DATA_SIZE);
printf("%d\n", bytes_received);
sendStatus[0]='s';
packetErrorSend(s,sendStatus,1,0);
}
bytes_written = write(fd,buf,bytes_received);
if(bytes_written == -1)
{
fprintf(stderr,"%s \n", "Client Error: Write error");
break;
}
}
if(bytes_received == -1)
{
fprintf(stderr,"%s \n", "Client Error: Error receiving file");
exit(0);
}
if(close(fd) != 0)
{
printf("%s \n", "Client Error: File did not close successfully");
exit(0);
}
close(s);
}
return 0;
}
server:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "packetErrorSend.h"
#include <sys/time.h>
#define SERVER_PORT "5432"
#define MAX_PENDING 5
int main(int argc, char *argv[])
{
struct addrinfo hints;
struct addrinfo *rp, *result;
char file[MAX_PACKET_DATA_SIZE];
int s, new_s;
int bytes_transferred = 0;
int fd; //file descriptor
char status[1];
/* Build address data structure */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
/* Get local address info */
if ((s = getaddrinfo(NULL, argv[1], &hints, &result)) != 0 )
{
fprintf(stderr, "%s: getaddrinfo: %s\n", argv[0], gai_strerror(s));
exit(1);
}
/* Iterate through the address list and try to perform passive open */
for (rp = result; rp != NULL; rp = rp->ai_next)
{
if ((s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1 )
{
continue;
}
if (!bind(s, rp->ai_addr, rp->ai_addrlen))
{
break;
}
close(s);
}
if (rp == NULL)
{
perror("stream-talk-server: bind");
exit(1);
}
if (listen(s, MAX_PENDING) == -1)
{
perror("stream-talk-server: listen");
close(s);
exit(1);
}
freeaddrinfo(result);
/* Wait for connection, then receive and print text */
while(1)
{
for(int i = 0; i < sizeof(file); i++)
{
file[i] = '\0';
}
if ((new_s = accept(s, rp->ai_addr, &(rp->ai_addrlen))) < 0)
{
perror("stream-talk-server: accept");
close(s);
exit(0);
}
if ((bytes_transferred = recv(new_s,file,sizeof(file),0)) > 0)
{
fd = open(file,O_RDONLY);
if(fd < 0)
{
perror("open");
status[0] = 'e';
send(new_s,status,1,0);
close(new_s);
exit(0);
}
status[0] = 's';
send(new_s,status,1,0);
int datasent = 0;
bytes_transferred = 1;
while(bytes_transferred > 0)
{
status[0] = s;
bytes_transferred = read(fd,file,MAX_PACKET_DATA_SIZE);
printf("%d\n",bytes_transferred);
datasent = send(new_s,file,bytes_transferred,0);
if (datasent < 0)
{
perror("send");
break;
}
recv(new_s,status,1,0);
printf("before while: %c \n", status[0]);
while(status[0] == 'e')
{
recv(new_s,status,1,0);
send(new_s,file,bytes_transferred,0);
printf("in while: %c \n", status[0]);
}
}
if (bytes_transferred == 0)
{
break;
}
else if(bytes_transferred == -1)
{
perror("read");
close(new_s);
exit(0);
}
}
}
close(fd);
close(new_s);
return 0;
}