File Transfer Using BSD Socket

File Transfer Using BSD Socket

I have discussed basic socket operation by sending a simple message in the post : https://www.absouls.com/2021/02/bsd-socket-programming.html  . 

Now, with that socket, I am going to send a single file from the client to the server. Primarily, I am gonna send a text file by reading each line from that file to make it simple. Later, we will discuss sending multiple files or other types. Here are the basic steps:

On the server side,

On client side,



Steps in the Server Side:

int sockfd = socket(domain_name, com_type, protocol)


sockfd: socket descriptor, an integer (File Descriptor)

domain_name: integer, communication domain e.g., AF_INET (IPv4 protocol) , AF_INET6 (IPv6 protocol)

com_type: 

1. SOCK_STREAM: TCP(reliable, connection oriented)

2. SOCK_DGRAM: UDP(unreliable, connectionless)

protocol: Protocol value for Internet Protocol(IP), which is 0. This is the same number which appears on protocol field in the IP header of a packet


int sockfd = socket(AF_INET, SOCK_STREAM, 0);

                if (sockfd == -1) {

                    perror("Unable to create Socket");

                    exit(1);

                }



Bind

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);


After creation of the socket, bind() function binds the socket to the address and port number specified in nwServerAddr(custom data structure). 

               // 4. Bind to Server Address

                if (bind(sockfd, (const struct sockaddr *) &nwServerAddr, sizeof(nwServerAddr)) == -1) {

                    perror("Unable to Bind");

                    exit(1);

                 }


Listen

int listen(int sockfd, int listen_port);


It puts the server socket in a passive mode, where it waits for the client to approach the server to make a connection. The listen_port, defines the maximum length to which the queue of pending connections for sockfd may grow.



                // 5. Listen Socket for incoming File

                if (listen(sockfd, LISTEN_PORT) == -1) {

                    perror("Error in Socket Listening");

                    exit(1);

                }




Accept

int new_fd = accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);


It extracts the first connection request on the queue of pending connections for the listening socket, sockfd, creates a new connected socket, and returns a new file descriptor referring to that socket. 

               // 6. Accept connection for concurrency number

                socklen_t adlen = sizeof(nwClientAddr);

                int cfd = accept(sockfd, (struct sockaddr *) &nwClientAddr, &adlen);

                if (cfd == -1) {

                    perror("Error in Accepting Connection for ");

                    exit(1);

                }


At this point, the connection is established between the client and server, and they are ready to transfer data.


Receive (File name & data) :

int recv(sockfd, buf, len, 0);


sockfd : Socket file descriptor which already connected with server listen port.

buf : character buffer which is suppose to send to server

len : buffer length


1. At first, we will receive the file name.


            // 7. Receive incoming file from client

    char filename[MAX_NAME] = {0};

    if (recv(cfd, filename, MAX_NAME,0) == -1) {

perror("Unable to receive file due to connection or file error");

exit(1);

            }


2. After receiving the file name, we will create a file pointer and create an empty file with same name.

3. Open the file with "wb" mode. Receive the file data from client and write into the file



void fileWriter(char *fileName, int sockfd, FILE *fp) {

// 10.1 Declare data length

int n;

// 10.2 Declare and Initialize buffer size

printf("%s file Receiving is started in Connection ID: %d\n", fileName, sockfd);

// 10.3 Receive data from socket and save into buffer

char buff[BUFFER_SIZE] = {0};

while(1) {

n = recv(sockfd, buff, BUFFER_SIZE,0);

if (n == -1) {

perror("Error in Receiving File");

exit(1);

}

if(n <= 0) {

break;

}

// 10.4 Read File Data from buffer and Write into file

if (fwrite(buff, sizeof(char), n, fp) != n) {

perror("Error in Writing File");

exit(1);

}

// 10.5 Allocate buffer

memset(buff, '\0', BUFFER_SIZE);

}

fclose(fp);

 }


Steps in the Client Side:

Create Socket

int sockfd = socket(domain_name, com_type, protocol)


sockfd: socket descriptor, an integer (File Descriptor)

domain_name: integer, communication domain e.g., AF_INET (IPv4 protocol) , AF_INET6 (IPv6 protocol)


com_type: 

1. SOCK_STREAM: TCP(reliable, connection oriented)

2. SOCK_DGRAM: UDP(unreliable, connectionless)

protocol: Protocol value for Internet Protocol(IP), which is 0. This is the same number which appears on protocol field in the IP header of a packet.

// 2. Create TCP Socket

int sockfd = socket(AF_INET, SOCK_STREAM, 0);

if (sockfd < 0) {

perror("Unable to create Socket");

exit(1);

        }

Connect

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);


The connect() system call connects the socket referred to by the file descriptor sockfd to the address specified by addr. Server’s address and port is specified in addr.

// 6. Client will connect after server bind

if (connect(sockfd, (const struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) {

perror("Unable to Connect");

exit(1);

}


Send :

int send(sockfd, buf, len, 0);


sockfd : Socket file descriptor which is already connected with the server listen port.

buf : character buffer which is supposed to send to server

len : buffer length


1. At first, we will send the file name just like the opposite of server-side

        

     printf("%s file Sending is started \n",fileName);

if (send(sockfd, fileName, MAX_NAME, 0) == -1) {

perror("Unable to send Filename");

exit(1);

}

// 12. Create File pointers

FILE *filePointer = fopen(fileName, "rb");

if (filePointer == NULL) {

perror("Unable to open the file");

exit(1);

        }


2. After sending the file name, we will open the file with "rb" mode

3. Send the file data from client.



void fileSender(FILE *filePointer, int sockfd) {

// 13.2 Declare and Initalize the buffer for a single file


char lineBuffer[BUFFER_SIZE] = {0};

int maxLen = 0;

// 13.3 Read the data from file in a loop

while ((maxLen = fread(lineBuffer, sizeof(char), BUFFER_SIZE, filePointer)) > 0) {

if (maxLen != BUFFER_SIZE && ferror(filePointer)) {

    perror("Unable to read file");

    exit(1);

}

// 13.4 Send each line from buffer through TCP socket

if (send(sockfd, lineBuffer, maxLen,0) == -1) {

    perror("Unable to send file");

    exit(1);

}

memset(lineBuffer, '\0', BUFFER_SIZE);

}

fclose(filePointer);

 }


Prepare

$ git clone https://github.com/arupcsedu/BSDSocketProgramming.git

$ cd BSDSocketProgramming 

Build and Run Server

$ cd SockSFileTransfer/Server

$ g++ Server.cpp -o Server

$ ./Server 

Build and Run Client

$ cd ..
$ cd Client
$ dd if=/dev/zero of=s1 bs=10MB count=1 //This is for creating 10MB file
$ g++ Client.cpp -o Client
$ ./Client s1 127.0.0.1

Source code URL: