// Sample network sockets code - UDP Client.
// Written for COMP3331 by Andrew Bennett, October 2019.
// ============================================================
// Modified by Wei Song (Tutor for COMP3331/9331), October 2021
// Modifications:
// - UDP --> TCP


#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>

/*

A good reference for C sockets programming (esp. structs and syscalls):
https://beej.us/guide/bgnet/html/multi/index.html

And for information on C Threads:
https://www.gnu.org/software/libc/manual/html_node/ISO-C-Threads.html

One of the main structs used in this program is the "sockaddr_in" struct.
See: https://beej.us/guide/bgnet/html/multi/ipstructsdata.html#structs

struct sockaddr_in {
    short int          sin_family;  // Address family, AF_INET
    unsigned short int sin_port;    // Port number
    struct in_addr     sin_addr;    // Internet address
    unsigned char      sin_zero[8]; // Same size as struct sockaddr
};

*/


// Server host and port number are defined here for simple usage, but for some
// lab/assignment requires, they may need to be passed from command line parameter
// which should be obtained from the second parameter *argv[] of the main() function
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 12000

#define BUF_LEN 1024

// Get the "name" (IP address) of who we're communicating with.
char *get_name(struct sockaddr_in *sa, char *name);

// Populate a sockaddr_in struct with the specified IP / port to connect to.
void fill_sockaddr(struct sockaddr_in *sa, char *ip, int port);

// A wrapper function for fgets, similar to Python's built-in 'input' function.
void get_input(char *buf, char *msg);


int main(int argc, char *argv[]) {

    // Array that we'll use to store the data we're sending / receiving.
    char buf[BUF_LEN] = {0};

    // Temporary array used to store the name of the client when printing.
    char name[BUF_LEN] = {0};

    // Create the client's socket.
    //
    // The first parameter indicates #the address family; in particular,
    // `AF_INET` indicates that the underlying network is using IPv4.
    //
    // The second parameter indicates that the socket is of type
    // SOCK_DGRAM, which means it is a UDP socket (rather than a TCP
    // socket, where we use SOCK_STREAM).
    //
    // This returns a file descriptor, which we'll use with our send /
    // recv functions later.
    int sock_fd = socket(AF_INET, SOCK_STREAM, 0);

    // A wrapper function for fgets, similar to Python's built-in
    // 'input' function.
    while (1) {
        get_input(buf, "===== Please type any messsage you want to send to server: =====\n");

        // Create the sockaddr that the client will use to send data to the
        // server.
        struct sockaddr_in sockaddr_to;
        fill_sockaddr(&sockaddr_to, SERVER_IP, SERVER_PORT);

        // Now that we have a socket and a message, we send the message
        // through the socket to the server.
        //
        // Note the difference between UDP sendto() and TCP send() calls.
        // In TCP we do not need to attach the destination address to the
        // packet, while in UDP we explicilty specify the destination
        // address + port number for each message.
        int connection_result = connect(sock_fd, &sockaddr_to, sizeof(sockaddr_to));
        int numbytes = send(sock_fd, buf, strlen(buf), 0);
        printf("[send] %s\n", buf);


        // Create the sockaddr that the client will use to receive data from
        // the server.
        struct sockaddr_in sockaddr_from;

        // We need to create a variable to store the length of the sockaddr
        // we're using here, which the recvfrom function can update if it
        // stores a different amount of information in the sockaddr.
        socklen_t from_len = sizeof(sockaddr_from);

        // Wait for the reply from the server.
        numbytes = recv(sock_fd, buf, BUF_LEN, 0);

        // Null-terminate the result, and remove the newline (if present).
        buf[numbytes] = '\0';
        buf[strcspn(buf, "\n")] = '\0';

        printf("[recv] Received %d bytes from %s:%d: %s\n", numbytes,
                get_name(&sockaddr_from, name),
                ntohs(sockaddr_from.sin_port), buf);
        
        get_input(buf, "\nDo you want to continue(y/n) :\n");
        if (strcmp(buf, "n") == 0) {
            break;
        }
    }

    return 0;
}


// Wrapper function for fgets, similar to Python's built-in 'input'
// function.
void get_input(char *buf, char *msg) {
    printf("%s", msg);
    fgets(buf, BUF_LEN, stdin);
    buf[strcspn(buf, "\n")] = '\0'; // Remove the newline
}

// Populate a `sockaddr_in` struct with the IP / port to connect to.
void fill_sockaddr(struct sockaddr_in *sa, char *ip, int port) {

    // Set all of the memory in the sockaddr to 0.
    memset(sa, 0, sizeof(struct sockaddr_in));

    // IPv4.
    sa->sin_family = AF_INET;

    // We need to call `htons` (host to network short) to convert the
    // number from the "host" endianness (most likely little endian) to
    // big endian, also known as "network byte order".
    sa->sin_port = htons(port);
    sa->sin_addr.s_addr = inet_addr(SERVER_IP);
}

// Get the "name" (IP address) of who we're communicating with.
char *get_name(struct sockaddr_in *sa, char *name) {
    inet_ntop(sa->sin_family, &(sa->sin_addr), name, BUF_LEN);
    return name;
}

Resource created Saturday 04 September 2021, 10:47:46 AM, last modified Monday 04 October 2021, 08:19:04 AM.

file: TCPClient.c


Back to top

COMP3331/COMP9331 21T3 (Computer Networks and Applications) is powered by WebCMS3
CRICOS Provider No. 00098G