|
|
@@ -0,0 +1,210 @@ |
|
|
// Client side implementation of UDP client-server model |
|
|
#include <stdio.h> |
|
|
#include <stdlib.h> |
|
|
#include <unistd.h> |
|
|
#include <string.h> |
|
|
#include <sys/types.h> |
|
|
#include <sys/socket.h> |
|
|
#include <arpa/inet.h> |
|
|
#include <netinet/in.h> |
|
|
#include <netdb.h> |
|
|
#include <sys/time.h> |
|
|
#include <pthread.h> |
|
|
#include <string.h> |
|
|
|
|
|
// #include "Packet.h" |
|
|
// #include "Utility.h" |
|
|
|
|
|
#define BUFFER_LEN 512 |
|
|
#define TIME_OUT 5000 |
|
|
#define MAX_DATA 1024 // milliseconds |
|
|
|
|
|
// Socket variable |
|
|
int sock_fd, n, len, dest_port; |
|
|
struct sockaddr_in server_address; |
|
|
struct hostent *dest_hostnet; |
|
|
|
|
|
// sliding window variable |
|
|
int buffer_size, window_size, last_ack_rcv, last_frame_send; |
|
|
|
|
|
void create_socket() { |
|
|
sock_fd = socket(AF_INET, SOCK_DGRAM, 0); |
|
|
if (sock_fd < 0) { |
|
|
perror("socket creation failed"); |
|
|
exit(EXIT_FAILURE); |
|
|
} |
|
|
} |
|
|
|
|
|
void fill_server_info() { |
|
|
memset(&server_address,0,sizeof(server_address)); |
|
|
server_address.sin_family = AF_INET; |
|
|
bcopy(dest_hostnet->h_addr, (char*)&server_address.sin_addr, dest_hostnet->h_length); |
|
|
|
|
|
server_address.sin_port = htons(dest_port); |
|
|
} |
|
|
|
|
|
void send_message() { |
|
|
char msg[20]; |
|
|
scanf("%s",msg); |
|
|
sendto(sock_fd, msg, strlen(msg), MSG_CONFIRM, (const struct sockaddr *) &server_address, sizeof(server_address)); |
|
|
} |
|
|
|
|
|
int get_ack_index() { |
|
|
return 0; |
|
|
} |
|
|
|
|
|
void* receive_ack(int* arr_ack_state, unsigned long* arr_frame_time) { |
|
|
|
|
|
char* buffer[buffer_size]; |
|
|
memset(&buffer,0,sizeof(buffer)); |
|
|
|
|
|
int ack_len; |
|
|
while(1) { |
|
|
ack_len = recvfrom(sock_fd, (char*) buffer, buffer_size, MSG_WAITALL, (struct sockaddr *) &server_address, &len); |
|
|
|
|
|
int ack_index = get_ack_index(); |
|
|
int error_ack = 1; |
|
|
if (!error_ack) { |
|
|
if (last_ack_rcv < ack_index && ack_index <= last_frame_send) { |
|
|
arr_ack_state[ack_index - (last_ack_rcv + 1 )] = 1; |
|
|
} else { |
|
|
struct timeval now; |
|
|
gettimeofday(&now, NULL); |
|
|
arr_frame_time[ack_index - (last_ack_rcv + 1)] = now.tv_usec; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
// void receive_ack() { |
|
|
// char* buffer[buffer_size]; |
|
|
// memset(&buffer,0,sizeof(buffer)); |
|
|
|
|
|
// n = recvfrom(sock_fd, (char*) buffer, buffer_size, MSG_DONTWAIT, (struct sockaddr *) &server_address, &len); |
|
|
|
|
|
// buffer[n] = '\0'; |
|
|
// printf("Server : %s\n", buffer); |
|
|
// } |
|
|
|
|
|
int step_to_slide(int* arr_ack_state) { |
|
|
if (arr_ack_state[0]) { |
|
|
int nb_step = 1; |
|
|
for (int i=0; i<window_size; i++) { |
|
|
if (!arr_ack_state[i]) { |
|
|
break; |
|
|
} |
|
|
nb_step++; |
|
|
} |
|
|
return nb_step; |
|
|
} |
|
|
return 0; |
|
|
} |
|
|
|
|
|
void slide_window(int step, int* arr_ack_state, int* arr_frame_send, int* arr_frame_time) { |
|
|
if (step == 0) return; |
|
|
|
|
|
for (int i=0; i<window_size-step; i++) { |
|
|
arr_ack_state[i] = arr_ack_state[i+step]; |
|
|
arr_frame_send[i] = arr_frame_send[i+step]; |
|
|
arr_frame_time[i] = arr_frame_time[i+step]; |
|
|
} |
|
|
for (int i=window_size-step; i<window_size; i++) { |
|
|
arr_frame_send[i] = 0; |
|
|
arr_ack_state[i] = 0; |
|
|
} |
|
|
last_ack_rcv += step; |
|
|
last_frame_send = last_ack_rcv + window_size; |
|
|
} |
|
|
|
|
|
int main(int argc, char* argv[]) { |
|
|
char *file_name; |
|
|
|
|
|
if (argc == 6) { |
|
|
file_name = argv[1]; |
|
|
window_size = atoi(argv[2]); |
|
|
buffer_size = atoi(argv[3]); |
|
|
dest_hostnet = gethostbyname(argv[4]); |
|
|
dest_port = atoi(argv[5]); |
|
|
} else { |
|
|
perror("Command format: ./sendfile <filename> <windowsize> <buffersize> <destination_ip> <destination_port>"); |
|
|
exit(EXIT_FAILURE); |
|
|
} |
|
|
|
|
|
create_socket(); |
|
|
fill_server_info(); |
|
|
|
|
|
int arr_ack_state[window_size], arr_frame_send[window_size]; |
|
|
unsigned long arr_frame_time[window_size]; |
|
|
|
|
|
memset(arr_ack_state, 0, sizeof(arr_ack_state)); |
|
|
memset(arr_frame_send, 0, sizeof(arr_frame_send)); |
|
|
for (int i=0; i<window_size; i++) { |
|
|
struct timeval start; |
|
|
gettimeofday(&start, NULL); |
|
|
arr_frame_time[i] = start.tv_usec; |
|
|
} |
|
|
|
|
|
int nb_frame = 10; |
|
|
int frame_number; |
|
|
|
|
|
last_ack_rcv = -1; |
|
|
last_frame_send = last_ack_rcv + window_size; |
|
|
|
|
|
pthread_t rcv_ack_thread; |
|
|
int rcv_ack_thread_state; |
|
|
|
|
|
// rcv_ack_thread_state = pthread_create(&rcv_ack_thread,NULL,&receive_ack,NULL); |
|
|
|
|
|
int max_buf_len = 1024 * buffer_size; |
|
|
char buffer[max_buf_len]; |
|
|
int read_finish = 0; |
|
|
FILE *file = fopen(file_name,"r"); |
|
|
|
|
|
int finish_read = 0; |
|
|
int cnt = 0; |
|
|
while (!finish_read) { |
|
|
int buf_len = fread(buffer,1,max_buf_len,file); |
|
|
if (buf_len == max_buf_len) { |
|
|
char remain[1]; |
|
|
int remain_len = fread(remain,1,1,file); |
|
|
if (remain_len == 0) { |
|
|
finish_read = 1; |
|
|
} |
|
|
int remain_pointer = fseek(file,-1,SEEK_CUR); |
|
|
} else if (buf_len < max_buf_len) { |
|
|
finish_read = 1; |
|
|
} |
|
|
|
|
|
int finish_send = 0; |
|
|
while (!finish_send) { |
|
|
int nb_step = step_to_slide(arr_ack_state); |
|
|
slide_window(nb_step,arr_ack_state,arr_frame_send,arr_frame_time); |
|
|
|
|
|
for (int i=0; i<window_size; i++) { |
|
|
frame_number = last_ack_rcv + i + 1; |
|
|
if (frame_number < nb_frame) { |
|
|
char message[MAX_DATA]; |
|
|
int idx; |
|
|
for(idx = 0; idx<MAX_DATA && idx < strlen(buffer) ; idx++){ |
|
|
message[idx] = buffer[MAX_DATA*frame_number+idx]; |
|
|
} |
|
|
|
|
|
struct timeval now; |
|
|
gettimeofday(&now, NULL); |
|
|
unsigned long diff_time = now.tv_usec - arr_frame_time[i]; |
|
|
int loss = !arr_ack_state[i] && diff_time > TIME_OUT; |
|
|
|
|
|
if (!arr_frame_send[i] || loss) { |
|
|
// send_message(); |
|
|
arr_frame_send[i] = 1; |
|
|
arr_frame_time[i] = now.tv_usec; |
|
|
} |
|
|
} |
|
|
} |
|
|
finish_send = 1; |
|
|
} |
|
|
} |
|
|
|
|
|
close(sock_fd); |
|
|
return 0; |
|
|
} |