#include #include #include #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////// #define BUF 1024 #define PORT 6543 /////////////////////////////////////////////////////////////////////////////// int main(int argc, char **argv) { int create_socket; char buffer[BUF]; struct sockaddr_in address; int size; int isQuit; //////////////////////////////////////////////////////////////////////////// // CREATE A SOCKET // https://man7.org/linux/man-pages/man2/socket.2.html // https://man7.org/linux/man-pages/man7/ip.7.html // https://man7.org/linux/man-pages/man7/tcp.7.html // IPv4, TCP (connection oriented), IP (same as server) if ((create_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("Socket error"); return EXIT_FAILURE; } //////////////////////////////////////////////////////////////////////////// // INIT ADDRESS // Attention: network byte order => big endian memset(&address, 0, sizeof(address)); // init storage with 0 address.sin_family = AF_INET; // IPv4 // https://man7.org/linux/man-pages/man3/htons.3.html address.sin_port = htons(PORT); // https://man7.org/linux/man-pages/man3/inet_aton.3.html if (argc < 2) { inet_aton("127.0.0.1", &address.sin_addr); } else { inet_aton(argv[1], &address.sin_addr); } //////////////////////////////////////////////////////////////////////////// // CREATE A CONNECTION // https://man7.org/linux/man-pages/man2/connect.2.html if (connect(create_socket, (struct sockaddr *)&address, sizeof(address)) == -1) { // https://man7.org/linux/man-pages/man3/perror.3.html perror("Connect error - no server available"); return EXIT_FAILURE; } // ignore return value of printf printf("Connection with server (%s) established\n", inet_ntoa(address.sin_addr)); //////////////////////////////////////////////////////////////////////////// // RECEIVE DATA // https://man7.org/linux/man-pages/man2/recv.2.html size = recv(create_socket, buffer, BUF - 1, 0); if (size == -1) { perror("recv error"); } else if (size == 0) { printf("Server closed remote socket\n"); // ignore error } else { buffer[size] = '\0'; printf("%s", buffer); // ignore error } do { printf(">> "); if (fgets(buffer, BUF - 1, stdin) != NULL) { int size = strlen(buffer); // remove new-line signs from string at the end if (buffer[size - 2] == '\r' && buffer[size - 1] == '\n') { size -= 2; buffer[size] = 0; } else if (buffer[size - 1] == '\n') { --size; buffer[size] = 0; } isQuit = strcmp(buffer, "quit") == 0; ////////////////////////////////////////////////////////////////////// // SEND DATA // https://man7.org/linux/man-pages/man2/send.2.html // send will fail if connection is closed, but does not set // the error of send, but still the count of bytes sent if ((send(create_socket, buffer, size + 1, 0)) == -1) { // in case the server is gone offline we will still not enter // this part of code: see docs: https://linux.die.net/man/3/send // >> Successful completion of a call to send() does not guarantee // >> delivery of the message. A return value of -1 indicates only // >> locally-detected errors. // ... but // to check the connection before send is sense-less because // after checking the communication can fail (so we would need // to have 1 atomic operation to check...) perror("send error"); break; } ////////////////////////////////////////////////////////////////////// // RECEIVE FEEDBACK // consider: reconnect handling might be appropriate in somes cases // How can we determine that the command sent was received // or not? // - Resend, might change state too often. // - Else a command might have been lost. // // solution 1: adding meta-data (unique command id) and check on the // server if already processed. // solution 2: add an infrastructure component for messaging (broker) // size = recv(create_socket, buffer, BUF - 1, 0); if (size == -1) { perror("recv error"); break; } else if (size == 0) { printf("Server closed remote socket\n"); // ignore error break; } else { buffer[size] = '\0'; printf("<< %s\n", buffer); // ignore error if (strcmp("OK", buffer) != 0) { fprintf(stderr, "<< Server error occured, abort\n"); break; } } } } while (!isQuit); //////////////////////////////////////////////////////////////////////////// // CLOSES THE DESCRIPTOR if (create_socket != -1) { if (shutdown(create_socket, SHUT_RDWR) == -1) { // invalid in case the server is gone already perror("shutdown create_socket"); } if (close(create_socket) == -1) { perror("close create_socket"); } create_socket = -1; } return EXIT_SUCCESS; }