diff --git a/DIRECTORY.md b/DIRECTORY.md index 476fa945..3453ca35 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -3,6 +3,8 @@ ## Client Server * [Client](https://github.com/TheAlgorithms/C/blob/master/client_server/client.c) * [Server](https://github.com/TheAlgorithms/C/blob/master/client_server/server.c) + * [Tcp Full Duplex Client](https://github.com/TheAlgorithms/C/blob/master/client_server/tcp_full_duplex_client.c) + * [Tcp Full Duplex Server](https://github.com/TheAlgorithms/C/blob/master/client_server/tcp_full_duplex_server.c) * [Tcp Half Duplex Client](https://github.com/TheAlgorithms/C/blob/master/client_server/tcp_half_duplex_client.c) * [Tcp Half Duplex Server](https://github.com/TheAlgorithms/C/blob/master/client_server/tcp_half_duplex_server.c) * [Udp Client](https://github.com/TheAlgorithms/C/blob/master/client_server/udp_client.c) diff --git a/client_server/tcp_full_duplex_client.c b/client_server/tcp_full_duplex_client.c new file mode 100644 index 00000000..bf15eda1 --- /dev/null +++ b/client_server/tcp_full_duplex_client.c @@ -0,0 +1,173 @@ +/** + * @file + * @author [NVombat](https://github.com/NVombat) + * @brief Client-side implementation of [TCP Full Duplex + * Communication](http://www.tcpipguide.com/free/t_SimplexFullDuplexandHalfDuplexOperation.htm) + * @see tcp_full_duplex_server.c + * + * @details + * The algorithm is based on the simple TCP client and server model. However, + * instead of the server only sending and the client only receiving data, + * The server and client can both send and receive data simultaneously. This is + * implemented by using the `fork` function call so that in the server the child + * process can recieve data and parent process can send data, and in the client + * the child process can send data and the parent process can receive data. It + * runs an infinite loop and can send and receive messages indefinitely until + * the user exits the loop. In this way, the Full Duplex Form of communication + * can be represented using the TCP server-client model & socket programming + */ + +#include /// For the type in_addr_t and in_port_t +#include /// For structures returned by the network database library - formatted internet addresses and port numbers +#include /// For in_addr and sockaddr_in structures +#include /// For specific bit size values of variables +#include /// Variable types, several macros, and various functions for performing input and output +#include /// Variable types, several macros, and various functions for performing general functions +#include /// Various functions for manipulating arrays of characters +#include /// For macro definitions related to the creation of sockets +#include /// For definitions to allow for the porting of BSD programs +#include /// For miscellaneous symbolic constants and types, and miscellaneous functions + +#define PORT 10000 /// Define port over which communication will take place + +/** + * @brief Utility function used to print an error message to `stderr`. + * It prints `str` and an implementation-defined error + * message corresponding to the global variable `errno`. + * @returns void + */ +void error() +{ + perror("Socket Creation Failed"); + exit(EXIT_FAILURE); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + /** Variable Declarations */ + uint32_t + sockfd; ///< socket descriptors - Like file handles but for sockets + char sendbuff[1024], + recvbuff[1024]; ///< character arrays to read and store string data + /// for communication + + struct sockaddr_in + server_addr; ///< asic structures for all syscalls and functions that + /// deal with internet addresses. Structures for handling + /// internet addresses + + /** + * The TCP socket is created using the socket function. + * + * AF_INET (Family) - it is an address family that is used to designate the + * type of addresses that your socket can communicate with + * + * SOCK_STREAM (Type) - Indicates TCP Connection - A stream socket provides + * for the bidirectional, reliable, sequenced, and unduplicated flow of data + * without record boundaries. Aside from the bidirectionality of data flow, + * a pair of connected stream sockets provides an interface nearly identical + * to pipes. + * + * 0 (Protocol) - Specifies a particular protocol to be used with the + * socket. Specifying a protocol of 0 causes socket() to use an unspecified + * default protocol appropriate for the requested socket type. + */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + error(); + } + + /** + * Server Address Information + * + * The bzero() function erases the data in the n bytes of the memory + * starting at the location pointed to, by writing zeros (bytes + * containing '\0') to that area. + * + * We bind the server_addr to the internet address and port number thus + * giving our socket an identity with an address and port where it can + * listen for connections + * + * htons - The htons() function translates a short integer from host byte + * order to network byte order + * + * htonl - The htonl() function translates a long integer from host byte + * order to network byte order + * + * These functions are necessary so that the binding of address and port + * takes place with data in the correct format + */ + bzero(&server_addr, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(PORT); + server_addr.sin_addr.s_addr = htonl(INADDR_ANY); + + printf("Client is running...\n"); + + /** + * Connects the client to the server address using the socket descriptor + * This enables the two to communicate and exchange data + */ + connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); + + printf("Client is connected...\n"); + + /** + * Communication between client and server + * + * The bzero() function erases the data in the n bytes of the memory + * starting at the location pointed to, by writing zeros (bytes + * containing '\0') to that area. The variables are emptied and then + * ready for use + * + * The fork function call is used to create a child and parent process + * which run and execute code simultaneously + * + * The child process is used to send data and after doing so + * sleeps for 5 seconds to wait for the parent to receive data + * + * The parent process is used to receive data and after doing so + * sleeps for 5 seconds to wait for the child to send data + * + * The server and client can communicate indefinitely till one of them + * exits the connection + * + * Since the exchange of information between the server and client takes + * place simultaneously this represents FULL DUPLEX COMMUNICATION + */ + pid_t pid; + pid = fork(); + if (pid == 0) /// Value of 0 is for child process + { + while (1) + { + bzero(&sendbuff, sizeof(sendbuff)); + printf("\nType message here: "); + fgets(sendbuff, 1024, stdin); + send(sockfd, sendbuff, strlen(sendbuff) + 1, 0); + printf("\nMessage sent!\n"); + sleep(5); + // break; + } + } + else /// Parent Process + { + while (1) + { + bzero(&recvbuff, sizeof(recvbuff)); + recv(sockfd, recvbuff, sizeof(recvbuff), 0); + printf("\nSERVER: %s\n", recvbuff); + sleep(5); + // break; + } + } + + /// Close Socket + close(sockfd); + printf("Client is offline...\n"); + return 0; +} diff --git a/client_server/tcp_full_duplex_server.c b/client_server/tcp_full_duplex_server.c new file mode 100644 index 00000000..9c2a0fae --- /dev/null +++ b/client_server/tcp_full_duplex_server.c @@ -0,0 +1,195 @@ +/** + * @file + * @author [NVombat](https://github.com/NVombat) + * @brief Server-side implementation of [TCP Full Duplex + * Communication](http://www.tcpipguide.com/free/t_SimplexFullDuplexandHalfDuplexOperation.htm) + * @see tcp_full_duplex_server.c + * + * @details + * The algorithm is based on the simple TCP client and server model. However, + * instead of the server only sending and the client only receiving data, + * The server and client can both send and receive data simultaneously. This is + * implemented by using the `fork` function call so that in the server the child + * process can recieve data and parent process can send data, and in the client + * the child process can send data and the parent process can receive data. It + * runs an infinite loop and can send and receive messages indefinitely until + * the user exits the loop. In this way, the Full Duplex Form of communication + * can be represented using the TCP server-client model & socket programming + */ + +#include /// For the type in_addr_t and in_port_t +#include /// For structures returned by the network database library - formatted internet addresses and port numbers +#include /// For in_addr and sockaddr_in structures +#include /// For specific bit size values of variables +#include /// Variable types, several macros, and various functions for performing input and output +#include /// Variable types, several macros, and various functions for performing general functions +#include /// Various functions for manipulating arrays of characters +#include /// For macro definitions related to the creation of sockets +#include /// For definitions to allow for the porting of BSD programs +#include /// For miscellaneous symbolic constants and types, and miscellaneous functions + +#define PORT 10000 /// Define port over which communication will take place + +/** + * @brief Utility function used to print an error message to `stderr`. + * It prints `str` and an implementation-defined error + * message corresponding to the global variable `errno`. + * @returns void + */ +void error() +{ + perror("Socket Creation Failed"); + exit(EXIT_FAILURE); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + /** Variable Declarations */ + uint32_t sockfd, + conn; ///< socket descriptors - Like file handles but for sockets + char recvbuff[1024], + sendbuff[1024]; ///< character arrays to read and store string data + /// for communication + + struct sockaddr_in server_addr, + client_addr; ///< asic structures for all syscalls and functions that + /// deal with internet addresses. Structures for handling + /// internet addresses + socklen_t ClientLen; /// size of address + + /** + * The TCP socket is created using the socket function + * + * AF_INET (Family) - it is an address family that is used to designate the + * type of addresses that your socket can communicate with + * + * SOCK_STREAM (Type) - Indicates TCP Connection - A stream socket provides + * for the bidirectional, reliable, sequenced, and unduplicated flow of data + * without record boundaries. Aside from the bidirectionality of data flow, + * a pair of connected stream sockets provides an interface nearly identical + * to pipes + * + * 0 (Protocol) - Specifies a particular protocol to be used with the + * socket. Specifying a protocol of 0 causes socket() to use an unspecified + * default protocol appropriate for the requested socket type + */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + error(); ///< Error if the socket descriptor has a value lower than 0 - + /// socket wasnt created + } + + /** + * Server Address Information + * + * The bzero() function erases the data in the n bytes of the memory + * starting at the location pointed to, by writing zeros (bytes + * containing '\0') to that area + * + * We bind the server_addr to the internet address and port number thus + * giving our socket an identity with an address and port where it can + * listen for connections + * + * htons - The htons() function translates a short integer from host byte + * order to network byte order + * + * htonl - The htonl() function translates a long integer from host byte + * order to network byte order + * + * These functions are necessary so that the binding of address and port + * takes place with data in the correct format + */ + bzero(&server_addr, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(PORT); + server_addr.sin_addr.s_addr = htonl(INADDR_ANY); + + printf("Server is running...\n"); + + /** + * This binds the socket descriptor to the server thus enabling the server + * to listen for connections and communicate with other clients + */ + if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) + { + error(); /// If binding is unsuccessful + } + /** + * This is to listen for clients or connections made to the server + * + * The limit is currently at 5 but can be increased to listen for + * more connections + * + * It listens to connections through the socket descriptor + */ + listen(sockfd, 5); + + printf("Server is listening...\n"); + + /** + * When a connection is found, a socket is created and connection is + * accepted and established through the socket descriptor + */ + conn = accept(sockfd, (struct sockaddr *)NULL, NULL); + + printf("Server is connected...\n"); + + /** + * Communication between client and server + * + * The bzero() function erases the data in the n bytes of the memory + * starting at the location pointed to, by writing zeros (bytes + * containing '\0') to that area. The variables are emptied and then + * ready for use + * + * The fork function call is used to create a child and parent process + * which run and execute code simultaneously + * + * The child process is used to receive data and after doing so + * sleeps for 5 seconds to wait for the parent to send data + * + * The parent process is used to send data and after doing so + * sleeps for 5 seconds to wait for the child to receive data + * + * The server and client can communicate indefinitely till one of them + * exits the connection + * + * Since the exchange of information between the server and client takes + * place simultaneously this represents FULL DUPLEX COMMUNICATION + */ + pid_t pid; + pid = fork(); + if (pid == 0) /// Value of 0 is for child process + { + while (1) + { + bzero(&recvbuff, sizeof(recvbuff)); + recv(conn, recvbuff, sizeof(recvbuff), 0); + printf("\nCLIENT : %s\n", recvbuff); + sleep(5); + // break; + } + } + else /// Parent process + { + while (1) + { + bzero(&sendbuff, sizeof(sendbuff)); + printf("\nType message here: "); + fgets(sendbuff, 1024, stdin); + send(conn, sendbuff, strlen(sendbuff) + 1, 0); + printf("\nMessage Sent!\n"); + sleep(5); + // break; + } + } + + /// Close socket + close(sockfd); + printf("Server is offline...\n"); + return 0; +}