Home > C, Programming > UDP Transfer File Socket dengan Bahasa C

UDP Transfer File Socket dengan Bahasa C

September 18, 2013 Leave a comment Go to comments

Wah, terakhir posting di blog kayaknya udah setahun yang lalu. Sebenernya udah dari beberapa bulan yang lalu pengen posting, cuman gak kesampaian gara2 ada kesibukan yang lain, malah akhirnya ide posting pun hilang. Misalnya postingan ini sebenernya udah pengen ditulis dari tahun kemaren. Langsung saja ke topik utama, kali ini yang akan saya share adalah source code program yang melakukan transfer file dengan menggunakan UDP. Karena pengiriman menggunakan UDP, digunakan checksum untuk melakukan pengecekan apakah file yang diterima client sempurna (sesuai yang dikirimkan server). Yang akan di-share disini adalah source code server maupun client-nya. Secara garis besar bagaimana program ini berjalan bisa dilihat di comment yang ditambahkan di source code. Semoga cukup jelas, kalau ada pertanyaan, jangan segan2 untuk bertanya😀

Source code server:

// Load library standar untuk soket dan beberapa library standar
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <strings.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
// Server menggunakan port 8888 untuk transfer file
#define SERVERPORT 8888
// Ukuran buffer yang digunakan untuk setiap pengiriman adalah 1 KB
#define MAXBUF 1024
// Deklarasi fungsi checksum yang akan digunakan untuk mengecek apakah paket UDP yang diterima sempurna
unsigned int checksum(char *bufdata, int nbyte);
// Program utama
int main(void) {
	// Inisialisasi socket
	int socket1;
	int addrlen;
	struct sockaddr_in xferServer, xferClient;
	int returnStatus;
	// Variabel datasend berisi byte yang akan dikirim
	unsigned char *datasend;
	// Membuat socket, dengan setting IPv4 dan UDP
	socket1 = socket(AF_INET, SOCK_DGRAM, 0);
	if (socket1 == -1){
		fprintf(stderr, "Could not create socket!\n");
		exit(1);
	}
	xferServer.sin_family = AF_INET;
	xferServer.sin_addr.s_addr = INADDR_ANY;
	xferServer.sin_port = htons(SERVERPORT);
	// Melakukan bind ke socket
	returnStatus = bind(socket1, (struct sockaddr*)&xferServer, sizeof(xferServer));
	if (returnStatus == -1){
		fprintf(stderr, "Could not bind to socket!\n");
		exit(1);
	}
	// Looping sambil menunggu koneksi dari client
	for(;;){
		// File descriptor
		int fd;
		// variabel counter
		int i, readCounter, writeCounter;
		// buffer dari data sebelum dikirim
		char buf[MAXBUF];
		// buffer dari nama file yang diinginkan
		char filename[MAXBUF];
		// mendefinisikan variabel timeout
		struct timeval timeout;
		// tidak ada timeout untuk proses menunggu client yang terhubung
        timeout.tv_sec = 0;
        timeout.tv_usec = 0;
		// mengatur proses receive socket sesuai dengan timeout di atas
		if (setsockopt (socket1, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0) fprintf(stderr, "Could not set timeout!\n");
		// menunggu permintaan pengiriman file dari client
		addrlen = sizeof(xferClient);
		i = 0;
		printf("Waiting for Client...\n");
		// menerima nama file yang diinginkan dari client
		if ((readCounter = recvfrom(socket1, filename, MAXBUF, 0, (struct sockaddr*)&xferClient, &addrlen)) > 0){
			i += readCounter;
		}
		if (readCounter == -1){ // nama file gagal diterima server
			fprintf(stderr, "Could not read filename from socket!\n");
			close(socket1);
			continue;
		}
		// nama file berhasil diterima server
		filename[i] = '\0';
		printf("Reading file %s\n", filename);
		// mulai melakukan pembacaan file yang diinginkan
		fd = open(filename, O_RDONLY);
		if (fd == -1){ // file tidak bisa dibuka
			fprintf(stderr, "Could not open file for reading!\n");
			close(socket1);
			continue;
		}
		readCounter = 0;
		int part = 0;
		// looping pembacaan file sampai akhir, dengan ukuran 1 KB setiap kali baca, yang dimasukkan ke variabel buf
		while((readCounter = read(fd, buf, MAXBUF)) > 0){
			// inisialisasi variabel yang menandakan pengiriman sukses dengan 0
			int xferOK = 0;
			// mendapatkan checksum dari data yang akan dikirim
			unsigned int cksmS = checksum(buf, readCounter);
			// alokasi ukuran datasend berdasarkan ukuran readCounter ditambah 4 byte dari checksum
			datasend = (unsigned char *) malloc ((4+readCounter)*sizeof(char));
			// check apakah alokasi berhasil
			if (datasend == NULL) { fprintf(stderr, "Could not allocate memory for datasend!\n"); exit(1); }
			// inisialisasi datasend dengan bit 0
			bzero(datasend, (4+readCounter));
			// mengisi 4 byte pertama datasend dengan checksum
			memcpy(datasend, (void *) &cksmS, 4);
			// mengisi byte2 setelah checksum dengan data yang akan dikirim
			memcpy(datasend+4, buf, readCounter);
			// looping pengiriman data sampai, client mengirimkan notifikasi penerimaan sempurna (sesuai checksum)
			while (!xferOK){
				// string xferStat = "!" menandakan file belum diterima client dengan sempurna
				// string xferStat = "%" menandakan file belum diterima client dengan sempurna
				char xferStat[1] = "!";
				printf("Sending Part: %d\n", part);
				// mengirimkan paket datasend ke client
				writeCounter = sendto(socket1, datasend, (readCounter+4), 0, (struct sockaddr*)&xferClient, sizeof(xferClient));
				// memberikan timeout untuk proses penerimaan notifikasi dari client ke server (5 detik)
				timeout.tv_sec = 5;
				if (setsockopt (socket1, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0) fprintf(stderr, "Could not allocate memory for datasend!\n");
				// menerima hasil notifikasi dari client
				recvfrom(socket1, xferStat, 1, 0, (struct sockaddr*)&xferClient, &addrlen);
				if(xferStat[0] == '%') { // data diterima dengan sempurna
					xferOK = 1;
					part++;
				} else { // data dikirim ulang
					printf("Sending The Same Part: %d\n", part);
				}
			}
		}
		// seluruh file telah berhasil dibaca, mengirimkan notifikasi bahwa pengiriman telah selesai
		// notifikasi dari server berisi string "#%&^$"
		char finish[5] = "#%&^$";
		sendto(socket1, finish, strlen(finish), 0, (struct sockaddr*)&xferClient, sizeof(xferClient));
		printf("Transfer File Completed\n");
		close(fd);
	}
	close (socket1);
	return 0;
}

// fungsi checksum yang digunakan untuk proses pengiriman
unsigned int checksum(char *bufdata, int nbyte){
	unsigned int cksum = 0;
	int i;
	for (i=0;i<nbyte;i++){
		unsigned int tes = (((unsigned int) bufdata[i]) << 24) >> (24 - 8*(i%4));
		cksum += tes;
	}
	return (~cksum)+1;
}

Berhubung code untuk client-nya mirip sekali dengan server, jadi untuk client comment-nya gak saya kasih ya

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

#define SERVERPORT 8888
#define MAXBUF 1024

unsigned int checksum(char *bufdata, int nbyte);

int main(int argc, char* argv[]){
	int sockd;
	int counter;
	int fd;
	int addrlen;
	struct sockaddr_in xferServer, xferClient;
	char *buf;
	char *data;
	int returnStatus;
	unsigned int cksmC;
	buf = (char *) malloc ((MAXBUF+4)*sizeof(char));
	if (buf == NULL){ fprintf(stderr, "Could not allocate memory for buf!\n"); exit(1); }
	if (argc < 3){
		fprintf(stderr, "Usage: %s <ip address> <filename> [dest filename]\n", argv[0]);
		exit(1);
	}
	sockd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockd == -1){
		fprintf(stderr, "Could not create socket!\n");
		exit(1);
	}
	xferServer.sin_family = AF_INET;
	xferServer.sin_addr.s_addr = inet_addr(argv[1]);
	xferServer.sin_port = htons(SERVERPORT);
	returnStatus = sendto(sockd, argv[2], strlen(argv[2])+1, 0, (struct sockaddr*)&xferServer, sizeof(xferServer));
	if (returnStatus == -1){
		fprintf(stderr, "Could not send filename to server!\n");
		exit(1);
	}
	//shutdown(sockd, SHUT_WR);
	fd = open(argv[3], O_WRONLY | O_CREAT | O_APPEND);
	if (fd == -1){
		fprintf(stderr, "Could not open destination file, using stdout.\n");
		fd = 1;
	}
	addrlen = sizeof(xferServer);
	int recving = 1;
	int part = 0;
	while (recving){
		// string ok = "!" menandakan data yang diterima tidak sempurna
		// string ok = "%" menandakan data yang diterima sempurna
		char ok[1] = "!";
		printf("Part %d\n", part);
		bzero(buf, (MAXBUF+4));
		counter = recvfrom(sockd, buf, MAXBUF+4, 0, (struct sockaddr*)&xferServer, &addrlen);
		if(buf[0] == '#' && buf[1] == '%' && buf[2] == '&' && buf[3] == '^' && buf[4] == '$'){
			// akhir loop penerimaan file dari server
			recving = 0;
		} else {
			cksmC = checksum(buf, counter);
			if(cksmC == 0){
				data = (char *) malloc ((counter-4)*sizeof(char));
	            if (data == NULL){ fprintf(stderr, "Could not allocate memory for data!\n"); exit(1); }
        	    bzero(data, (counter-4));
				memcpy(data, buf+4, (counter-4));
				//printf("%d\n", counter);
				write(fd, data, (counter-4));
				char ok[1] = "%";
				part++;
				sendto(sockd, ok, strlen(ok), 0, (struct sockaddr*)&xferServer, sizeof(xferServer));
			} else {
				fprintf(stderr, "Checksum not Valid, Request to Resend\n");
				sendto(sockd, ok, strlen(ok), 0, (struct sockaddr*)&xferServer, sizeof(xferServer));
			}
		}
	}
	close(sockd);
	return 0;
}

unsigned int checksum(char *bufdata, int nbyte){
	unsigned int cksum = 0;
	int i;
	for (i=0;i<nbyte;i++){
		unsigned int tes = (((unsigned int) bufdata[i]) << 24) >> (24 - 8*(i%4));
		cksum += tes;
	}
	return (~cksum)+1;
}
Categories: C, Programming
  1. agustian
    December 11, 2013 at 2:05 pm

    min mau tanya…
    [dest filename] maksudnya apa ? menggunakan Ip localhost atw bikin sendiri ? trus dest filename it ap ?

  2. agustian
    December 11, 2013 at 2:39 pm

    ane udah dpt min jawaban dr pertanyaan sebelumnya..
    skrg ane mau tanya kenapa file yg ditransfer dr server ke client tidak bisa dibuka tp menampilkan “access denied” ???
    mohon bantuannuya min..
    terimakasih

    • December 11, 2013 at 2:54 pm

      oh itu berarti permission di client-nya mesti di-set dulu, pake chmod 755
      kalo mau di code juga bisa ditambahin baris code system(concat(“chmod 755 “, filename) misalnya, jadi ngubah permissionnya otomatis

  3. agustian
    December 12, 2013 at 2:55 pm

    udah ane cba set permission di client dan berhasil tp wktu ane coba juga di codenya malah error, ane salah baris wktu tambahin code-nya, yg bner dibaris yg mana gan ?
    trus yg sukses cuma pas buka file .txt aja, gmn kalo file yg .doc .pdf .mp3 ama yg lainnya gan ?
    terimakasih banyak gan solusinya sangat membantu ane.

    • December 17, 2013 at 12:50 pm

      sori2 baru buka blog lagi, kemaren minggu uas soalnya

      potongan source code yang ane kasih itu masih psudocode itungannya, rasanya fungsi
      concat input parameternya gak gitu, intinya sih pake system(input), yang inputnya command “chmod 755 nama_file”

      mestinya sih gak buat .txt aja, atau mungkin pake fopen aja cuman pake mode binary deh

  4. April 28, 2014 at 2:16 pm

    wih keren
    tp kak ko udp ada checksum nya?

    • May 1, 2014 at 9:04 pm

      soalnya kalo UDP itu paketnya nyampe bener atau salah nggak diperiksa, jadi si program client yg ngecek apa paketnya yang kekirim bener apa nggak, kalo paketnya ada yang corrupt dia bakal minta kirim lagi dari server

  5. dema
    November 16, 2014 at 4:04 pm

    program clientnya gak mau,
    yang muncul malah :: Usage: ./client [dest filename] (pada clientnya)
    sedangkan di server sudah waiting…
    tolong pencerahannya master🙂
    tenkyu hhe😀

  6. February 11, 2016 at 8:14 pm

    kalo ingin checksum nya 2 bit gmn mas?

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: