TCP File Transfer with Socket Programming in Unix Using C: A Complete Guide
🎯 Introduction
TCP (Transmission Control Protocol) is a fundamental protocol in computer networking that provides reliable and ordered delivery of data over IP networks. In this comprehensive guide, we will delve into TCP file transfer using socket programming in Unix with the C programming language. By understanding the underlying concepts and exploring practical examples, you will gain the knowledge and skills to develop efficient file transfer applications.
Socket programming enables the creation of network applications that communicate over TCP/IP networks. Through sockets, processes running on different machines can establish connections, exchange data, and enable robust file transfer capabilities. By utilizing the power of socket programming, you can harness the reliability and performance benefits of TCP to build robust file transfer systems.
In this guide, we will walk you through the server and client code for TCP file transfer in Unix using C. You will gain insights into the essential functions and techniques involved in establishing connections, transmitting data, and handling file transfers. We will provide detailed explanations and highlight key points to enhance your understanding.
By the end of this guide, you will have a solid foundation in TCP file transfer and socket programming, empowering you to create your own efficient file transfer applications.
🎯 Server Side Code and Explanation
Source Code
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
#include <fcntl.h>
int main() {
    int sd, cd;
    char buf[1000] = "", fname[10];
    struct sockaddr_in ser;
    // Create a socket
    sd = socket(AF_INET, SOCK_STREAM, 0);
    if (sd < 0)
        printf("SOCKET NOT CREATED\n");
    bzero(&ser, sizeof(struct sockaddr_in));
    ser.sin_family = AF_INET;
    ser.sin_port = htons(1101);
    inet_aton("localhost", &ser.sin_addr);
    int b = bind(sd, (struct sockaddr *)&ser, sizeof(ser));
    printf("BIND VALUE: %d\n", b);
    listen(sd, 5);
    for (;;) {
        cd = accept(sd, NULL, NULL);
        int pid = fork();
        if (pid == 0) {
            printf("accept value %d\n", cd);
            read(cd, buf, 1000);
            int fd = open(buf, O_RDONLY);
            read(fd, buf, 1000);
            write(cd, buf, strlen(buf));
            printf("MESSAGE FROM CLIENT: %s\n", buf);
            close(cd);
        }
    }
    close(sd);
    return 0;
}
Explanation
We include necessary header files for networking, file operations, and standard I/O.
The main() function serves as the entry point for the program.
We declare variables for the socket descriptor (sd), client descriptor (cd), and buffer for data transmission (buf).
A structure sockaddr_in is defined to store server address information.
We create a socket using socket() with the domain (AF_INET), type (SOCK_STREAM for TCP), and protocol (0 for default).
If the socket creation fails, an error message is printed.
We initialize the server address structure, setting the family (AF_INET) and port (1101) to listen on.
The server IP address is set to "localhost" using inet_aton().
The bind() function binds the socket to the specified address and port.
The listen() function is called to listen for incoming connections, with a backlog of 5.
The server enters an infinite loop to accept client connections.
Upon accepting a client connection, a child process is forked.
In the child process, the client's message is read from the socket.
The requested file is opened and its contents are read into the buffer.
The buffer is written back to the client socket.
The received message from the client is printed.
The child process closes the client socket and terminates.
The server continues listening for new connections.
🎯 Client Side Source and Explanation
Source Code
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
#include <fcntl.h>
int main() {
    int sd, cd;
    char buf[1000] = "", buf1[1000] = "";
    struct sockaddr_in ser;
    // Create a socket
    sd = socket(AF_INET, SOCK_STREAM, 0);
    if (sd < 0)
        printf("SOCKET NOT CREATED\n");
    bzero(&ser, sizeof(struct sockaddr_in));
    ser.sin_family = AF_INET;
    ser.sin_port = htons(1101);
    inet_aton("localhost", &ser.sin_addr);
    // Connect to the server
    connect(sd, (struct sockaddr *)&ser, sizeof(ser));
    for (;;) {
        printf("ENTER THE MESSAGE: ");
        scanf("%s", buf);
        write(sd, buf, strlen(buf));
        read(sd, buf, 1000);
        printf("RECEIVED FROM SERVER: %s\n", buf);
    }
    close(sd);
    return 0;
}
Explanation:
We include necessary header files for networking, file operations, and standard I/O.
The main() function serves as the entry point for the program.
We declare variables for the socket descriptor (sd), client descriptor (cd), and buffers for sending and receiving data (buf and buf1).
A structure sockaddr_in is defined to store server address information.
We create a socket using socket() with the domain (AF_INET), type (SOCK_STREAM for TCP), and protocol (0 for default).
If the socket creation fails, an error message is printed.
We initialize the server address structure, setting the family (AF_INET) and port (1101) to connect to.
The server IP address is set to "localhost" using inet_aton().
The connect() function is called to establish a connection with the server.
A loop is started to allow multiple interactions with the server.
The user is prompted to enter a message.
The message is written to the server socket using write().
The response from the server is read into the buffer using read().
The received message from the server is printed.
Steps 11-14 repeat indefinitely until the program is terminated.
The client socket is closed.
🎯 Sample Output
SERVER:
cc udp.c -o udp
./udp
BIND VALUE: 0
accept value 4
MESSAGE FROM CLIENT:
#include<stdio.h>
main()
{
printf("hello");
}
CLIENT:
cc ftclient.c -o ftcli
./ftcli
ENTER THE MESSAGE
hello.c
RECEIVED FROM SERVER
#include<stdio.h>
main()
{
printf("hello");
}
Please note that the provided code is for sample purposes only and may need further modifications or error handling to be suitable for production use.
🎯 Conclusion
In this comprehensive guide, we explored TCP file transfer using socket programming in Unix with the C programming language. We examined the server and client code, providing detailed explanations to help you understand the underlying concepts.
By leveraging socket programming, you can create robust and efficient file transfer applications over TCP connections. The server code demonstrated how to set up a socket, bind it to an address, and listen for incoming client connections. The client code illustrated how to establish a connection with the server, send messages, and receive responses.
With this knowledge, you can extend the functionality of the provided code to suit your specific requirements. For example, you can enhance error handling, implement file chunking for large transfers, or add authentication mechanisms for secure file transfers.
Socket programming in C opens up a world of possibilities for networked applications, and TCP file transfer is just one application of this powerful technique. With further exploration and experimentation, you can build upon this foundation to create even more sophisticated networked solutions.
Remember to consider factors such as data integrity, network congestion, and security when developing your file transfer applications. By applying best practices and continuously improving your code, you can create reliable and efficient TCP file transfer systems.