Monitor stdin and the socket using select to avoid blocking on either one. Update the client so it monitors just two file descriptors: the socket with the server and stdin. Whenever a message is received on either, your program should read it and pass it to the correct output stream.

while (1) {
    num_read = read(STDIN_FILENO, buf, BUF_SIZE);
    if (num_read == 0) {
        break;
    }
    buf[num_read] = '\0';

    if (write(sock_fd, buf, num_read) != num_read) {
        perror("client: write");
        close(sock_fd);
        exit(1);
    }

    num_read = read(sock_fd, buf, sizeof(buf) - 1);
    if (num_read == 0) {
        break;
    }
    buf[num_read] = '\0';
    printf("[Server] %s", buf);
}