124 lines
3.8 KiB
C
124 lines
3.8 KiB
C
#include <arpa/inet.h>
|
|
#include <errno.h>
|
|
#include <netdb.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
|
|
// #define SERVER_IP_ADDRESS "149.165.171.99"
|
|
#define SERVER_IP_ADDRESS "127.0.0.1"
|
|
#define SERVER_PORT 60019
|
|
#define METHOD_VERSION 2
|
|
|
|
#define HEADER_SIZE 4
|
|
#define CHUNK_SIZE 1024
|
|
#define TOTAL_CHUNKS 1024
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int socket_desc;
|
|
struct sockaddr_in server;
|
|
|
|
// Create socket
|
|
socket_desc = socket(AF_INET, SOCK_DGRAM, 0);
|
|
|
|
// Server address structure
|
|
memset(&server, 0, sizeof(server));
|
|
server.sin_family = AF_INET;
|
|
server.sin_port = htons(SERVER_PORT);
|
|
inet_pton(AF_INET, SERVER_IP_ADDRESS, &(server.sin_addr));
|
|
|
|
// Send initial message to the server
|
|
// We want the entire file initially
|
|
sendto(socket_desc, "INI", 3, 0, (struct sockaddr *)&server, sizeof(server));
|
|
|
|
// Ack Buffer
|
|
char ack_buffer[TOTAL_CHUNKS];
|
|
for (int i = 0; i < TOTAL_CHUNKS; i++)
|
|
{
|
|
ack_buffer[i] = 0; // Initialize all to not received
|
|
}
|
|
|
|
// Buffer for entire file
|
|
char file_buffer[CHUNK_SIZE * TOTAL_CHUNKS];
|
|
|
|
FILE *file = fopen("received_ugbits.txt", "w");
|
|
|
|
printf("Listening for file chunks...\n");
|
|
|
|
// Set socket timeout to 5 seconds
|
|
struct timeval timeout;
|
|
timeout.tv_sec = 5;
|
|
timeout.tv_usec = 0;
|
|
setsockopt(socket_desc, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
|
|
|
// Listen for file messages from the server
|
|
listen_for_file:
|
|
while (1)
|
|
{
|
|
char buffer[CHUNK_SIZE + HEADER_SIZE];
|
|
socklen_t server_len = sizeof(server);
|
|
int recv_size = recvfrom(socket_desc, buffer, CHUNK_SIZE + HEADER_SIZE, 0, (struct sockaddr *)&server, &server_len);
|
|
|
|
if (recv_size < 0)
|
|
{
|
|
// Timeout occurred - no message received for 5 seconds
|
|
printf("No messages received for 5 seconds, stopping...\n");
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
buffer[recv_size] = '\0';
|
|
char chunkNum[HEADER_SIZE];
|
|
strncpy(chunkNum, buffer, HEADER_SIZE);
|
|
chunkNum[HEADER_SIZE] = '\0';
|
|
ack_buffer[atoi(chunkNum)] = 1; // Set buffer to RXed
|
|
|
|
if (METHOD_VERSION == 1) {
|
|
// Method 1: Write Chunk Directly to file
|
|
fseek(file, (atoi(chunkNum) - 1) * CHUNK_SIZE, SEEK_SET);
|
|
fwrite(buffer + HEADER_SIZE, 1, recv_size - HEADER_SIZE, file);
|
|
} else {
|
|
// Method 2: Store chunk in buffer var
|
|
memcpy(file_buffer + (atoi(chunkNum) - 1) * CHUNK_SIZE, buffer + HEADER_SIZE, recv_size - HEADER_SIZE);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If any chunk has not been received, request missing chunks
|
|
// This is accomplished by sending the ack buffer back to the server
|
|
int totalMissing = 0;
|
|
|
|
for (int i = 1; i <= TOTAL_CHUNKS; i++)
|
|
{
|
|
if (ack_buffer[i] != 1)
|
|
{
|
|
totalMissing++;
|
|
}
|
|
}
|
|
|
|
if (totalMissing != 0)
|
|
{
|
|
printf("Total missing chunks: %d, requesting retransmission...\n", totalMissing);
|
|
char request[TOTAL_CHUNKS + HEADER_SIZE] = "REQ";
|
|
memcpy(request + HEADER_SIZE, ack_buffer, TOTAL_CHUNKS);
|
|
sendto(socket_desc, request, strlen(request), 0, (struct sockaddr *)&server, sizeof(server));
|
|
goto listen_for_file;
|
|
}
|
|
|
|
// If we made it here, the file must be complete.
|
|
printf("File transfer complete!\n");
|
|
if (METHOD_VERSION == 2) {
|
|
// Method 2: Write entire buffer to file
|
|
fwrite(file_buffer, 1, CHUNK_SIZE * TOTAL_CHUNKS, file);
|
|
}
|
|
|
|
fclose(file);
|
|
close(socket_desc);
|
|
return 0;
|
|
}
|