Thread: simple dict client problem

  1. #1
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57

    Question simple dict client problem

    Hello there,
    Im am trying to write a simple dict client just to send the command DEFINE and receive the answer. I am hoping to get similar result to when i connect to dict via telnet (telnet dict.org dict). After i send a command DEFINE world02 Poland then i get the apropriate answer.


    In my program, the response is, no matter what i send:
    Code:
    220 pan.alephnull.com dictd 1.12.0/rf on Linux 3.0.0-14-server <auth.mime> <[email protected]>

    I dont know what am i doing wrong here. Here is my code:


    Code:
    #include<stdio.h>
    #include<string.h>    //strlen
    #include<sys/socket.h>
    #include<arpa/inet.h> //inet_addr
    #include <unistd.h>
    
    
    int main()
    {
        int socket_desc;
        struct sockaddr_in server;
        char *message , server_reply[5000];
    
    
        //Create socket
        socket_desc = socket(AF_INET , SOCK_STREAM , 0);
        if (socket_desc == -1)
        {
            printf("Could not create socket");
        }
    
    
        server.sin_addr.s_addr = inet_addr("216.18.20.172");
        server.sin_family = AF_INET;
        server.sin_port = htons(2628);
    
    
        //Connect to remote server
        if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0)
        {
            puts("connect error");
            return 1;
        }
    
    
        puts("Connected\n");
    
    
        //Send some data
        message = "DEFINE world02 Poland";
        if( send(socket_desc , message , strlen(message) , 0) < 0)
        {
            puts("Send failed");
            return 1;
        }
        puts("Data Send\n");
    
    
        //Receive a reply from the server
        if( recv(socket_desc, server_reply , 5000 , 0) < 0)
        {
            puts("recv failed");
        }
        puts("Reply received\n");
        puts(server_reply);
        close(socket_desc);
    
    
        return 0;
    }

    If anyone has any expirience in dict protocol and would be abble to aid me here i would be really gratefull for that.

  2. #2
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Looking at the samples at section 8 (page 23) of RFC 2229, the server will answer with the 220 message after the connection (see also Section 3 in that RFC).

    Since that's the only response you read, you don't get the result of your request.

    Notice also that the answer will probably be several lines, so you need to check for the 250 status code ("Command complete").

    Bye, Andreas

  3. #3
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57
    Quote Originally Posted by AndiPersti View Post
    Since that's the only response you read, you don't get the result of your request.
    Could you explain little bit more here? I am sending the Define command here to the server and i was hoping for a proper result. What am I doing wrong actully?
    Do i need to send any additional data or try to receive data in another way?

  4. #4
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57
    Okay I think I understand now after i look up the example. But still it does not work. Everytime im trying to send another command after the connection i get the same ansfer all the time (the one after connection, not command).

    Could you try to write an example command string for me?
    Last edited by bremenpl; 04-30-2013 at 03:44 AM.

  5. #5
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Ok, after a closer look at your code and the protocol I've noticed some problems:

    Code:
       //Connect to remote server
        if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0)
        {
            puts("connect error");
            return 1;
        }
        puts("Connected\n");
    As I told you already, you will get an answer from the server after you've tried to connect to it. Thus you need to read it and act appropriately. It's possible that the server will not accept your request. Thus, even if send() doesn't return an error there is no guarantee that you are connected.

    Code:
    message = "DEFINE world02 Poland";
    According to the protocol, a request must be terminated by CRLF ("\r\n"). See section 2.3 of the RFC.

    Code:
        if( recv(socket_desc, server_reply , 5000 , 0) < 0)
        {
            puts("recv failed");
        }
        puts("Reply received\n");
        puts(server_reply);
        close(socket_desc);
    recv() doesn't wait for the complete answer from the server, Thus you need to check if the string you recieved includes the terminating sequence, i.e. a single dot followed by CRLF. See section 2.4.3.
    You should also send the "QUIT" command to tell the server that you want to close the connection.

    Here's an example based on your code, which connects to the server, sends the "HELP" command and then closes the connection. It's just a rough outline I've hacked together the last half an hour and you really have to read the protocol for all the details.
    Code:
    #include<stdio.h>
    #include<string.h>    //strlen
    #include<sys/socket.h>
    #include<arpa/inet.h> //inet_addr
    #include <unistd.h>
     
    int main(void)
    {
        int socket_desc;
        struct sockaddr_in server;
        char server_reply[5000];
     
        //Create socket
        socket_desc = socket(AF_INET , SOCK_STREAM , 0);
        if (socket_desc == -1)
        {
            printf("Could not create socket");
        }
     
        server.sin_addr.s_addr = inet_addr("216.18.20.172");
        server.sin_family = AF_INET;
        server.sin_port = htons(2628);
     
        //Connect to remote server
        if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0)
        {
            puts("connect error");
            return 1;
        }
     
        puts("Connected");
        recv(socket_desc, server_reply , sizeof(server_reply) , 0);
        puts("Server answered with:");
        puts(server_reply);
        memset(server_reply, 0, sizeof(server_reply)); 
    
        puts("Now it's time for sending a request");
        send(socket_desc, "HELP\r\n", 6, 0);
    
        puts("Server returned:");
        ssize_t ret, len = 0;
        char answer[BUFSIZ];
        char *pos = answer;
        while ((ret = recv(socket_desc, server_reply , sizeof(server_reply) , 0)))
        {
            strncat(answer, server_reply, BUFSIZ - len);
            len += ret;
            
            if ((pos = strstr(pos, "\r\n.\r\n250")))
            {
                pos = strstr(pos + 6, "\n");
                *(pos + 1) = '\0';
                break;
            }
            else
                pos = answer + len;
        }
        puts(answer);
    
        send(socket_desc, "QUIT\r\n", 6, 0);
        memset(server_reply, 0, sizeof(server_reply));
        recv(socket_desc, server_reply, sizeof(server_reply), 0);
        puts("Connection closed, server replied with:");
        puts(server_reply);
    
        close(socket_desc);
        return 0;
    }
    Bye, Andreas
    Last edited by AndiPersti; 04-30-2013 at 02:31 PM.

  6. #6
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57
    Wow, i really aprichiate the effor you have took to help me, thank you!
    Basin on this code i can reach what i need. I do agree that no matter the time im doing this i see it hard to sometimes find things i need in the documentation.
    Thank you again !

  7. #7
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57
    Althrough I have one more question if you dont mind. Looking up the documentation, the status command is no differ than help if i understand correct. So i tried to send status instead of help by using your code. I improved the buffer from 6 to 8 in send and in strstr functions. After those changes i dont get any message back, my program is stuck in the while loop.

    I would rly aprichiate if you could explain a little more.

  8. #8
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Quote Originally Posted by bremenpl View Post
    Althrough I have one more question if you dont mind. Looking up the documentation, the status command is no differ than help if i understand correct. So i tried to send status instead of help by using your code. I improved the buffer from 6 to 8 in send and in strstr functions. After those changes i dont get any message back, my program is stuck in the while loop.

    I would rly aprichiate if you could explain a little more.
    It's time to do your homework, i.e. read the RFC.

    Quote Originally Posted by RFC 2229
    2.4. Responses
    Responses are of two kinds, status and textual.
    ...
    Status response lines begin with a 3 digit numeric code which is sufficient to distinguish all responses. Some of these may herald the subsequent transmission of text.
    ...
    2.4.3. Text Responses
    Before text is sent a numeric status response line, using a 1yz code, will be sent indicating text will follow.
    ...
    3.7. The STATUS Command
    STATUS

    3.7.1. Description
    Display some server-specific timing or debugging information. This information may be useful in debugging or tuning a DICT server. All DICT servers MUST implement this command (note, though, that the text part of the response is not specified and may be omitted).

    3.7.2. Responses
    210 (optional timing and statistical information here)
    This response code requires no special parameters.
    TL;DR
    You have to check each response if it starts with a three digit number. Only if the first digit is 1 a text message follows and you need the loop.

    Bye, Andreas

  9. #9
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57
    Thank you very much. Gonna handle it from here

  10. #10
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57
    One more thing though... Whats really weird is that when i use commands set as example in the manual, they always work (i mean for define, like define * penguin or define * shortcake). But now, when i change that work to lets say define * poland or any other worls, it crashes on the while again =/. I quickly modified the code to receive 2 status first 150 and then 151:

    Code:
    #include<stdio.h>#include<string.h>    //strlen
    #include<sys/socket.h>
    #include<arpa/inet.h> //inet_addr
    #include <unistd.h>
    
    
    #define WORLD_2_SEND "DEFINE * penguin\r\n"
    
    
    int main(void)
    {
        int socket_desc;
        struct sockaddr_in server;
        char server_reply[5000];
    
    
        //Create socket
        socket_desc = socket(AF_INET , SOCK_STREAM , 0);
        if (socket_desc == -1)
        {
            printf("Could not create socket");
        }
    
    
        server.sin_addr.s_addr = inet_addr("216.18.20.172");
        server.sin_family = AF_INET;
        server.sin_port = htons(2628);
    
    
        //Connect to remote server
        if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0)
        {
            puts("connect error");
            return 1;
        }
    
    
        puts("Connected");
        recv(socket_desc, server_reply , sizeof(server_reply) , 0);
        puts("Server answered with:");
        puts(server_reply);
        memset(server_reply, 0, sizeof(server_reply));
    
    
        puts("Now it's time for sending a request");
        send(socket_desc, WORLD_2_SEND, strlen(WORLD_2_SEND), 0);
    
    
        puts("Server returned 1:");
        recv(socket_desc, server_reply, sizeof(server_reply), 0);
        puts(server_reply);
        puts("Server returned 2:");
        ssize_t ret, len = 0;
        char answer[BUFSIZ];
        char *pos = answer;
        while ((ret = recv(socket_desc, server_reply , sizeof(server_reply) , 0)))
        {
            strncat(answer, server_reply, BUFSIZ - len);
            len += ret;
    
    
            if ((pos = strstr(pos, "\r\n.\r\n250")))
            {
                pos = strstr(pos + strlen(WORLD_2_SEND), "\n");
                *(pos + 1) = '\0';
                break;
            }
            else
                pos = answer + len;
        }
        puts(answer);
    
    
        send(socket_desc, "QUIT\r\n", 6, 0);
        memset(server_reply, 0, sizeof(server_reply));
        recv(socket_desc, server_reply, sizeof(server_reply), 0);
        puts("Connection closed, server replied with:");
        puts(server_reply);
    
    
        close(socket_desc);
        return 0;
    }
    This is for receiving 150 reply:
    Code:
    puts("Server returned 1:");
        recv(socket_desc, server_reply, sizeof(server_reply), 0);
        puts(server_reply);
    And the code after does 151 as just like you wrote it. What is the difference of penguin or poland that it crashes i dont get. It says it finds the maches in 150 reply. I thought maybe buffer is to small but thats not it.

  11. #11
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Quote Originally Posted by bremenpl View Post
    What is the difference of penguin or poland that it crashes i dont get. It says it finds the maches in 150 reply. I thought maybe buffer is to small but thats not it.
    It's way to small. "DEFINE * poland" will return 4 different definitions. One of them is the excerpt from the CIA World Factbook 2002 about Poland, which is 33806 characters long.

    What do you try to achieve? Do you want to write a client for DICT?
    Then you need to rethink your approach. You would need to be able to parse each response you get from the server. For example after the DEFINE command the server will answer with a 150 code which tells you how many definitions it will send. Each definition starts with the 151 code and ends with CRLF.CRLF. So you would need a loop which gets each definition, taking care that you have enough memory to store the definition text.

    You must also be able to handle error messages. E.g. if there are no definitions for a word, the server will anser with "552 No match".

    I've also found a C-library which provides a simple API to connect to a DICT server.

    Bye, Andreas

  12. #12
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57
    To be honest, i rly just need to be abble to receive the answer after define world02 poland, it has to be a simple dict client example (its an uni assignement). I had no clue the definition is so long, thank you for realising that for me. I know that in a proper program there shuld be all errors handlings etc. Would you mind sharing the lib with me? Ive looked for it but couldnt find. It might be usefull for future. I will also have to write a simple server that would ansfer me with some definition, so it might be usefull there as well.

  13. #13
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Quote Originally Posted by bremenpl View Post
    Would you mind sharing the lib with me? Ive looked for it but couldnt find.
    The link I've given you in my last post will lead you to the SourceForge project page of "libdict". There you can download the source code.

    Bye, Andreas

  14. #14
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57
    Ah its a link lol... Not used to this color :P. Thank you.

  15. #15
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57
    Hi again, i have one more question if you dont mind. My client runs ok now, althrough now i also need to write a server. So I do, but in one of the lines i am receiving segmentation error, which i understand is an event that occurs when i try to acces memory that doesnt exist(?)

    And this happens at this line:
    Code:
    *(pos + 1) = '\0';
    without it i can connect to my server and receive answer properly, but receiving answer from dict.org server is faulty.
    I have to honest with you, im not sure what is the need for this line.
    Would you mind explaining it?

    Here is the code of my very early 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 threading , link with lpthread
     
    void *connection_handler(void *);
     
    int main(int argc , char *argv[])
    {
        int socket_desc , new_socket , c , *new_sock;
        struct sockaddr_in server , client;
        char *message;
         
        //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 );
         
        //Bind
        if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
        {
            puts("bind failed");
            return 1;
        }
        puts("bind done");
         
        //Listen
        listen(socket_desc , 3);
         
        //Accept and incoming connection
        puts("Waiting for incoming connections...");
        c = sizeof(struct sockaddr_in);
        while( (new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
        {
            puts("Connection accepted");
             
            pthread_t sniffer_thread;
            new_sock = malloc(1);
            *new_sock = new_socket;
             
            if( pthread_create( &sniffer_thread , NULL ,  connection_handler , (void*) new_sock) < 0)
            {
                perror("could not create thread");
                return 1;
            }
             
            //Now join the thread , so that we dont terminate before the thread
            //pthread_join( sniffer_thread , NULL);
            puts("Handler assigned");
        }
         
        if (new_socket<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 messages to the client that he is connected
        message = "220 Connected to Aleksandra Gut dict server\r\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));
    //      puts(client_message);
    //  }
    
    
        read_size = recv(sock , client_message , 2000 , 0);
        
        puts("Received message from client:");
        puts(client_message);
    
    
        //Send message to the client how many definitions has been found.
        message = "150 1 definition retrieved\r\n";
        write(sock , message , strlen(message));
    
    
        //Send definition to the client.
        message = "151 Definicja Pingwina yo\nDefinicja Pingwina yo\nDefinicja Pingwina yo\n\r\n.\r\n250";
        write(sock , message , strlen(message));
        
        read_size = recv(sock , client_message , 2000 , 0);
    
    
        //Send finish connection to the client.
        message = "221 bye \r\n";
        write(sock , message , strlen(message));
         
        if(read_size == 0)
        {
            puts("Client disconnected");
            fflush(stdout);
        }
        else if(read_size == -1)
        {
            perror("recv failed");
        }
             
        //Free the socket pointer
        free(socket_desc);
         
        return 0;
    }
    And this is my client that works for what i need pretty well: (but not for connecting to the server i wrote. only after commenting the problem line):
    Code:
    #include<stdio.h>
    #include<string.h>    //strlen
    #include<sys/socket.h>
    #include<arpa/inet.h> //inet_addr
    #include <unistd.h>
    
    
    #define WORLD_2_SEND "DEFINE * penguin\r\n"
    #define ADDRESS "216.18.20.172" // dict.org
    #define PORT 2628
    
    
    int socket_desc;
    struct sockaddr_in server;
    char server_reply[500000];
    char prefix[3];
    //char nrOfDefinitionsFound[1];
    //unsigned int nrOfDefsInt = 0;
    
    
    void Close_Connection (void);
    void Print_Answers (void);
    
    
    int main(void)
    {
        //Create socket
        socket_desc = socket(AF_INET , SOCK_STREAM , 0);
        if (socket_desc == -1)
        {
            printf("Could not create socket");
        }
    
    
        server.sin_addr.s_addr = inet_addr(ADDRESS);
        server.sin_family = AF_INET;
        server.sin_port = htons(PORT);
    
    
        //Connect to remote server
        if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0)
        {
            puts("connect error");
            return 1;
        }
    
    
        puts("Connected");
        recv(socket_desc, server_reply , sizeof(server_reply) , 0);
        puts("Server answered with:");
        puts(server_reply);
        memset(server_reply, 0, sizeof(server_reply));
    
    
        puts("Now it's time for sending a request");
        send(socket_desc, WORLD_2_SEND, strlen(WORLD_2_SEND), 0);
    
    
        puts("Server returned 1:");
        recv(socket_desc, server_reply, sizeof(server_reply), 0);
    
    
        memcpy(prefix, server_reply, sizeof(char) * 3);
        
        if (0 == strcmp("150", prefix)) 
        {
           puts(server_reply);
    //     nrOfDefinitionsFound[0] = server_reply[4];
    //     nrOfDefsInt = nrOfDefinitionsFound[0] - '0';
    //     printf("defs found = %u\n", nrOfDefsInt);
    
    
           Print_Answers();
        }
        else if (0 == strcmp("552", prefix))
        {
           puts(server_reply);
           Close_Connection();
           return 1;
        }
    
    
        Close_Connection();
    
    
        return 0;
    }
    
    
    void Close_Connection (void)
    {
        send(socket_desc, "QUIT\r\n", 6, 0);
        memset(server_reply, 0, sizeof(server_reply));
        recv(socket_desc, server_reply, sizeof(server_reply), 0);
        puts("Connection closed, server replied with:");
        puts(server_reply);
    
    
        close(socket_desc);
    }
    
    
    void Print_Answers (void)
    {
        puts("Server returned 2:");
        ssize_t ret, len = 0;
        char answer[5000000];
        char *pos = answer;
        while ((ret = recv(socket_desc, server_reply , sizeof(server_reply) , 0)))
        {
            strncat(answer, server_reply, 5000000 - len);
            len += ret;
    
    
            if ((pos = strstr(pos, "\r\n.\r\n250")))
            {
                pos = strstr(pos + strlen(WORLD_2_SEND), "\n");
                *(pos + 1) = '\0';
                break;
            }
            else
                pos = answer + len;
        }
    
    
        puts(answer);
    }
    I hope this isnt to much already, but i would rly aprichiate if you could explain me this issue.
    Last edited by bremenpl; 05-05-2013 at 01:48 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Simple FTP client
    By Ravi25187 in forum C Programming
    Replies: 2
    Last Post: 05-06-2011, 04:09 PM
  2. Cost of dict
    By scott_ill in forum C# Programming
    Replies: 4
    Last Post: 07-09-2009, 08:06 AM
  3. Problem with simple socket client/server program
    By spencer88 in forum C Programming
    Replies: 6
    Last Post: 05-05-2009, 11:05 PM
  4. Simple NTP Client?
    By Kritical in forum Networking/Device Communication
    Replies: 11
    Last Post: 04-04-2006, 03:36 AM
  5. Simple? winsock client - server problem
    By knutso in forum Windows Programming
    Replies: 2
    Last Post: 03-26-2003, 04:51 AM

Tags for this Thread