1

I have two programs for server and client. My server can connect to multiple client. But the problem right now I am facing is that, I want to display some message from the server side to client side but I am unable to do that. Both the server and client program are provided below. I think the syntax that is preventing me to print the message on the client side is scanfwhich is used the code of client (second line of the while loop). I am not getting any solution for that about how to display the two messages from the server side when the client will get connected.

Problem 1: Server side messages that I want to display on the client side when client gets connected : (can be found in the new_connection_handler function)

 message = "This is connection handler\n";
 message = "Type something \n";

Problem 2:

Why I need to use the sleep (2) on the client side? If I do not use the sleep (2), then I cannot receive the data sent by the client on the client side. The data shows when I send something second time from the client side.

Problem 3:

Is it possible to write both the client and server code together and compile and run it using command line arguments?

Server Code:

#include<stdio.h>
#include<string.h>    //strlen
#include<stdlib.h>    //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h>    //write
#include<pthread.h> //for thread


 #define MAX_CLIENTS 5


//the thread function
void *new_connection_handler(void *);

int main(int argc , char *argv[])
{
    int socket_desc , client_sock , c , *new_sock;
    struct sockaddr_in server , client;


    //Create socket
    socket_desc = socket(AF_INET , SOCK_STREAM , 0);
    if (socket_desc == -1)
    {
        printf("Could not create socket");
    }


    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( 8888 );
    bzero (&server.sin_zero, 8);



    //Bind
    if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
    {
        //print the error message
        perror("bind failed. Error");
        return 1;
    }


    //Listen
    listen(socket_desc , MAX_CLIENTS);



    //Accept and incoming connection
    printf("Waiting for incoming connections\n");




    c = sizeof(struct sockaddr_in);
    while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
    {
        printf("Connection accepted");



        pthread_t thread_id;




        if( pthread_create( &thread_id , NULL ,  new_connection_handler , (void*) &client_sock) < 0)
        {
            perror("could not create thread");
            return 1;
        }



     printf("Handler assigned\n");
    }


    if (client_sock < 0)
    {
        perror("accept failed");
        return 1;
    }

    return 0;
}


void *new_connection_handler(void *socket_desc)
{
    //Get the socket descriptor
    int sock = *(int*)socket_desc;
    int read_size;
    char *message , client_message[2000];



    //Send some messages to the client
    message = "This is connection handler\n";
    write(sock , message , strlen(message));


    message = "Type something \n";
    write(sock , message , strlen(message));


    //Receive a message from client
    while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
    {
        //Send the message back to client
        write(sock , client_message , strlen(client_message));
    }



    if(read_size == 0)
    {
        printf("Client disconnected\n");
        fflush(stdout);
    }
    else if(read_size == -1)
    {
        perror("recv failed");
    }

    //Free the socket pointer
    free(socket_desc);

    return 0;
}

Client Code:

#include<stdio.h> //printf
#include<string.h>    //strlen
#include<sys/socket.h>    //socket
#include<arpa/inet.h> //inet_addr

int main(int argc , char *argv[])
{
    int sock;
    struct sockaddr_in server;
    char message[1000] , server_reply[2000];
    int len;

    //Create socket
    sock = socket(AF_INET , SOCK_STREAM , 0);
    if (sock == -1)
    {
        printf("Could not create socket");
    }
    puts("Socket created");

    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_family = AF_INET;
    server.sin_port = htons( 8888 );

    //Connect to remote server
    if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
    {
        perror("connect failed. Error");
        return 1;
    }

    puts("Connected\n");

    //keep communicating with server
    while(1)
    {
        printf("Enter message : ");
        scanf("%s" , message);


        //Send some data
        if( send(sock , message , strlen(message) , 0) < 0)
        {
            puts("Send failed");
            return 1;
        }
        sleep (2);
        //Receive a reply from the server
        if((len = recv(sock , server_reply , 2000 , 0)) < 0)
        {
            puts("recv failed");
            break;
        }

        puts("Server reply :");
        server_reply [len]='\0';
    printf("%s\n", server_reply);


    }

    close(sock);

    return 0;
}
user3751012
  • 533
  • 1
  • 8
  • 20
  • 2
    `new_sock = malloc(1);` is not good, should allocate `sizeof(int)`. What output you get at server and client? – Rohan Jul 09 '14 at 08:31
  • on client side : Socket created Connected Enter message : – user3751012 Jul 09 '14 at 08:34
  • on server side: Connection accepted Handler assigned – user3751012 Jul 09 '14 at 08:35
  • That is valid, your client is waiting on `scanf()`. May be you should have `recv()` before while loop on client. So that you can show message from server. – Rohan Jul 09 '14 at 08:38
  • Yes, I know this is correct. But is there any way that I can change scanf () so that I can also display the two messages (message = "This is connection handler\n"; message = "Type something \n";) as those are already received? – user3751012 Jul 09 '14 at 08:43
  • This problem seems even more general than the OP described. Under this configuration, it appears that server thinks it is sending messages, while the client is dropping them on the floor. – merlin2011 Jul 09 '14 at 08:59
  • @merlin2011 yes, so is there any way out so that client also receives and display the messages? – user3751012 Jul 09 '14 at 09:06
  • I haven't found one yet but it is not for lack of trying. :). On the other hand I have certainly written applications of this kind before which worked correctly. I will write am answer if I figure it out before someone else does. Good question though. I gave you +1 for ease of reproducibility. – merlin2011 Jul 09 '14 at 09:15
  • Add calls to `fflush(NULL);` before every socket operation.... (and before `sleep`). Learn about [poll(2)](http://man7.org/linux/man-pages/man2/poll.2.html), consider having some real [event loop](http://en.wikipedia.org/wiki/Event_loop); read [Advanced Linux Programming](http://advancedlinuxprogramming.com/) ... – Basile Starynkevitch Jul 09 '14 at 09:16
  • @BasileStarynkevitch I am reading this book but everything is not explained. I need to use the fflush (NULL) in the client part or server part? Please let me know. – user3751012 Jul 09 '14 at 09:45
  • Probably better to `fflush(NULL)` in both server and client parts. Also, check *every* [syscalls(2)](http://man7.org/linux/man-pages/man2/syscalls.2.html) (including `accept`) for failure. And as pointed out by *Rohan* your `malloc`-s are wrong (use [valgrind](http://valgrind.org/) ....). – Basile Starynkevitch Jul 09 '14 at 10:13
  • I am not using malloc (1) now. scanf() is restricting the two messages to get displayed on the client side. What is the point to use fflush (NULL). Using this not getting the messages after the client gets connected. – user3751012 Jul 09 '14 at 10:24
  • @merlin2011 any solution still now? – user3751012 Jul 09 '14 at 10:25
  • Side note: Even after your change, your thread creation loop is wrong, and has a potential race condition. Each launched thread utilizes the *same* address of the same automatic `client_sock` variable. You can/should send that value as an `intptr_t` which is cast-able legally to `void*` by *value*, and receive it in the launched thread by casting *back* to `intptr_t` (again, by *value*), and finally, back to `int` for your descriptor. – WhozCraig Jul 09 '14 at 10:38
  • How about my problem? I want to show the message on the client side. Any solution? – user3751012 Jul 09 '14 at 10:42
  • Also, your paren placement in your client code is incorrect for your `recv` expression. It should be `if((len = recv(sock , server_reply , 2000 , 0)) < 0)`, not `if(len = (recv(sock , server_reply , 2000 , 0)) < 0)`. Do you have compiler warnings turned on at all? – WhozCraig Jul 09 '14 at 10:46
  • I have fixed all other problems. I can connect client with server. The only thing I want now is to display the two messages when the client gets connected with the server. – user3751012 Jul 09 '14 at 10:50
  • So you "fixed" what I just commented on? Because that is paramount, as `len` will only ever be 0 or 1 with that bug (0 in all cases but a failed `recv`). – WhozCraig Jul 09 '14 at 10:51
  • Yes, that I had fixed earlier. I am only facing the problems which I have mentioned. Could you please explain why i need to use sleep (2) in the client side? – user3751012 Jul 09 '14 at 10:53
  • You don't need the sleep. your send/receive frames are out of sync. And your server-side echo-back isn't sending the right number of chars. it assumes the message it received is terminated, which it isn't because you sent based on `strlen`. I'd start by cleaning that up first, then get two terminal windows up and concentrate on your message sizes, as your `strlen` assumptions aren't valid. – WhozCraig Jul 09 '14 at 11:12

1 Answers1

2

Your frames are out of sync You open your client handling thread with two sends from the server. Without your "sleep", you pick up one, but not the other. your buffer sizes are also not being used correctly, as they're inconsistently being treated as terminated strings when in fact their send length is based on strlen (which is ok, so long as it is consistent).

I think this is what you're trying to do, with a few modifications:

Client Code

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

int main(int argc , char *argv[])
{
    int sock;
    struct sockaddr_in server;
    char message[1000] , server_reply[2000];
    int len;

    //Create socket
    sock = socket(AF_INET , SOCK_STREAM , 0);
    if (sock == -1)
    {
        printf("Could not create socket");
    }
    puts("Socket created");

    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_family = AF_INET;
    server.sin_port = htons( 8888 );

    //Connect to remote server
    if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
    {
        perror("connect failed. Error");
        return 1;
    }

    puts("Connected\n");

    //keep communicating with server
    while((len = recv(sock, server_reply, sizeof(server_reply), 0)) > 0)
    {
        printf("Server reply: %.*s", len, server_reply);

        printf("Enter message : ");
        if (fgets(message, sizeof(message), stdin) == NULL)
            break;

        //Send some data
        if( send(sock , message , strlen(message) , 0) < 0)
        {
            puts("Send failed");
            return 1;
        }
    }

    close(sock);

    return 0;
}

Server Code

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


#define MAX_CLIENTS 5


//the thread function
void *new_connection_handler(void *);

int main(int argc , char *argv[])
{
    int socket_desc , client_sock;
    struct sockaddr_in server , client;
    socklen_t c = sizeof(client);

    //Create socket
    socket_desc = socket(AF_INET , SOCK_STREAM , 0);
    if (socket_desc == -1)
    {
        printf("Could not create socket");
    }

    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( 8888 );
    bzero (&server.sin_zero, 8);

    //Bind
    if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
    {
        //print the error message
        perror("bind failed. Error");
        return 1;
    }

    //Listen
    listen(socket_desc , MAX_CLIENTS);

    //Accept and incoming connection
    printf("Waiting for incoming connections\n");

    c = sizeof(client);
    while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, &c)) )
    {
        printf("Connection accepted");
        pthread_t thread_id;

        if( pthread_create( &thread_id , NULL ,  new_connection_handler , (void*) (intptr_t)client_sock) < 0)
        {
            perror("could not create thread");
            return 1;
        }

        printf("Handler assigned\n");
    }


    if (client_sock < 0)
    {
        perror("accept failed");
        return 1;
    }

    return 0;
}


void *new_connection_handler(void *socket_desc)
{
    //Get the socket descriptor
    int sock = (intptr_t)socket_desc;
    int read_size = 0;
    char client_message[2000];

    static const char rdy[] = "READY\n";
    write(sock, rdy, sizeof(rdy)-1);

    //Receive a message from client
    while( (read_size = recv(sock , client_message , sizeof(client_message) , 0)) > 0 )
        write(sock , client_message , read_size);

    if(read_size == 0)
    {
        printf("Client disconnected\n");
        fflush(stdout);
    }
    else if(read_size == -1)
    {
        perror("recv failed");
    }

    return 0;
}

This still needs better join-logic on the client threads, but if you paste and compile each with appropriate flags I think it does what you're trying to achieve.

Best of luck.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141