1

I have just started learning socket programming.

Currently the server and the client are on the same workstation and everything seems to work. The server is running in c programming and my client is an android program. I managed to have a one way connection, sending data from client to server. I would like to send some string back to client.

Please advice me.

void *connection_handler(void *);

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

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

    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( 7800 );

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

    //Listen
    listen(socket_desc , 3);

    //Accept and incoming connection
    //puts("Waiting for incoming connections...");
    //c = sizeof(struct sockaddr_in);


    //Accept and incoming connection
    puts("Waiting for incoming connections...");
    c = sizeof(struct sockaddr_in);
    pthread_t thread_id;

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

        if( pthread_create( &thread_id , NULL ,  connection_handler , (void*) &client_sock) < 0)

        {
            perror("could not create thread");
            return 1;
        }

        //Now join the thread , so that we dont terminate before the thread
        //pthread_join( thread_id , NULL);
        puts("Handler assigned");
    }

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

    return 0;
}

/*
 * This will handle connection for each client
 * */
void *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 = "Greetings! I am your connection handler\n";
    write(sock , message , strlen(message));

    message = "Now type something and i shall repeat what you type \n";
    write(sock , message , strlen(message));

    //Receive a message from client
    while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
    {
        //end of string marker
        client_message[read_size] = '\0';

        printf("%s\n", client_message);

        //Send the message back to client
        write(sock , client_message , strlen(client_message));

        //clear the message buffer
        memset(client_message, 0, 2000);


    }

    if(read_size == 0)
    {
        //puts("Client disconnected");

        //fflush(stdout);
    }
    else if(read_size == -1)
    {
        perror("recv failed");
    }

    return 0;
} 
6
  • 3
    Can you be more specific what the problem is? Commented Mar 19, 2018 at 13:48
  • I can see a few problems and potential problems in your code, but as long as only one client is connected at a time then there should not be any problems with the transmissions to or from the client. Commented Mar 19, 2018 at 13:50
  • @Someprogrammerdude is hinting at this: '(void*) &client_sock' - think about what heppens if multiple clients attempt connections 'simultaneously'.... Commented Mar 19, 2018 at 17:48
  • If all 2000 bytes are recv'd, this: 'client_message[read_size] = '\0';' will write out-of-bounds. Commented Mar 19, 2018 at 17:49
  • @MartinJames That's why I added the note about only one client at a time connecting. Commented Mar 19, 2018 at 17:50

2 Answers 2

1

There are different ways to transmit data to another socket and it doesn't matter if it's either a server or a client.

write

As you did in your code, you can use the system call:

ssize_t write(int fd, const void *buf, size_t count);

It writes from the buf to the file related to the file descriptor fd. The return value will tell you if the message was sent correctly.

send, sendto, sendmsg

This is the second way you can send data to a socket. The only difference between write and send is the argument flags:

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

but if you set flag to 0, write and send will work in the same way. sendto and sendmsg are quite different from send because they have more arguments. You can get all information from man pages available online or in Linux.

http://man7.org/linux/man-pages/man2/send.2.html

Sign up to request clarification or add additional context in comments.

Comments

1
while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )

is wrong; you probably want to check >= 0 or (even better) express this in another way.

The lone

write(sock , message , strlen(message));

is not good:

  1. you should check the error code
  2. it will be very difficult for the receiver to split the result.
  3. write() will kill your program with SIGPIPE when the other end has been closed

I suggest something like

bool send_data(int fd, void const *data, size_t len) 
{
    while (len > 0) {
        ssize_t l = send(fd, data, len, MSG_NOSIGNAL);

        if (l > 0) {
            data += l;
            len -= l;
        } else if (l == 0) {
            fprintf(stderr, "this is ugly and can not happen...\n");
            break;
        } else if (errno == EINTR) {
            continue;
        } else {
            perror("send()");
            break;
        }
    }

    return len == 0;
}

and for string datatypes

bool send_string(int fd, char const *str)
{
    size_t l = strlen(str);
    uint32_t  l_be = htobe32(l);

    if ((uint32_t)(l) != l)
        return false;

    return (send_data(fd, &l_be, sizeof l_be) &&
            send_data(fd, str, l));
}

For receiving, you can implement recv_data() similarly to send_data() above. Depending on your memory allocation strategy, you can implement either

bool recv_string(int fd, char *str, size_t max_len, size_t *len)
{
    uint32_t  l_be;
    size_t l;

    if (!recv_data(fd, &l_be, sizeof l_be))
        return false;

    l = be32toh(l_be);
    if (l >= max_len)
        return false;

    if (!recv_data(fd, str, l))
        return false;

    str[l] = '\0';

    if (len)
        *len = l;

    return true;   
}

or write something which malloc() memory for the received data after reading the length.

Now, you can do on one side:

if (!send_string(fd, "foo") ||
    !send_string(fd, "bar") ||
    !recv_string(fd, resp, sizeof resp, NULL))
       error();

and on the other one

if (!recv_string(fd, req0, sizeof req0, NULL) ||
    !recv_string(fd, req1, sizeof req1, NULL) ||
    !send_string(fd, handle_request(req0, req1)))
        error();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.