LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   sockets: Send string to server (https://www.linuxquestions.org/questions/programming-9/sockets-send-string-to-server-459733/)

introuble 06-30-2006 08:10 AM

sockets: Send string to server
 
Ok .. I have the following function, which writes to a socket:

Code:

void sockwrite(int sockd, const void *buf)
{
        char *ptr = (char *)buf;
        size_t bytesleft = strlen(ptr);
        size_t bytessent = 0;

        while (bytesleft > 0) {
                bytessent = Write(sockd, ptr, bytesleft);
                ptr += bytessent;
                bytesleft -= bytessent;
        }
}

Now, I need to use this function to send to the server a string of the form:

Code:

"PASSWORD <a password>\r\n"
<a password> is stored in "pass", it's a char string.

I can do this two ways:

Code:

#1.
        sockwrite(s, "PASSWORD ");
        sockwrite(s, pass);
        sockwrite(s, "\r\n");

Code:

#2.
        char *buffer;       
        asprintf(&buffer, "PASSWORD %s\r\n", pass);
        sockwrite(s, buffer);

This is not the only string of this type I have to send though. Chances are I'll have to send a lot of strings of similar form. Question is: which method do I use? The first won't allocate a temporary storage location but expands over 3 lines [loss of clarity?]. The 2nd is clearer but allocates a temporary storage location for the string AND asprintf() is not POSIX compliant [GNU extension, will work on Linux/BSD .. and I can live with that :)]

So .. how should I do this? Any other methods?

burntfuse 06-30-2006 12:48 PM

You could also keep a global buffer that's the length of the longest string you'll have to send, and then do:

Code:

sprintf(buffer, [whatever]);
sockwrite(s, buffer);

Yeah, it's a bit messy, but it would reduce the number of lines of code each time you do something like this. Altogether, your first way might be the best as long as you don't have to convert numbers to strings or anything that you'd need printf for. It isn't really any harder to read, and it saves memory.

tuxdev 06-30-2006 01:16 PM

Socket descripters are file descripters in *nix. Just use fprintf.

graemef 06-30-2006 01:20 PM

You probably don't need to send the third line \r\n since it doesn't really provide anything extra. In which case your first approach would probably be better.

introuble 06-30-2006 02:47 PM

fprintf on a socket? No thanks.

I don't think a global, static allocated buffer is very memory savy/good practise.

The protocol requires that all messages end in "\r\n".

Well .. I guess I will indeed use the first method .. I suppose this gets rid of some portability problems [introducted by the use of asprintf].

jlinkels 06-30-2006 02:55 PM

If I am not mistaken, the function sockwrite hangs when the connection is interrupted or times out. Should bytessent not checked for being zero to indicate that there is nothing sent at all? Or did you omit this for simplicity? (and be nice to us, readers)

jlinkels

tuxdev 06-30-2006 04:44 PM

Using fprintf on a socket is fine. In fact, *nix sockets are designed to be used that way. You should not be using threads anyway, so what is the big deal?

introuble 07-01-2006 04:51 AM

Quote:

If I am not mistaken, the function sockwrite hangs when the connection is interrupted or times out. Should bytessent not checked for being zero to indicate that there is nothing sent at all? Or did you omit this for simplicity? (and be nice to us, readers)
Code:

bytessent = Write(sockd, ptr, bytesleft);
the Write() wrapper takes care of it.

jlinkels 07-01-2006 09:29 AM

Doesn't write return 0 (zero) if no bytes are being written? And since bytessent is 0, your program will remain in the loop.

jlinkels

introuble 07-01-2006 02:04 PM

Code:

ssize_t Write(int fd, const void *buf, size_t count)
{
        ssize_t nrbytes;

        if ((nrbytes = write(fd, buf, count)) == -1) {
                perror("write");
                exit(EXIT_FAILURE);
        }

        return nrbytes;
}

The purpoise of sockwrite() is to make sure buf is sent OR cause the program to exit.

jlinkels 07-01-2006 02:39 PM

Introuble,

Ok, at first I failed to see that Write was a different function from write.

Now, I know that someone else's code is always worse that someone's own, but still a comment which is meant as good advice.

First, I doubt whether leaving the program because of a write failure is the best thing to do. But since you know your program requirements best, it might be according to your needs.

However, if for any reason you ever would want to take any action as a result of a write failure you would not be able to do so as your program already exited. No clean-up, no error messages, no action in case of a simple time-out.

As a matter of fact, recently there was some discussion in this thread about leaving the program in a deeply nested exit.
http://www.linuxquestions.org/questi...d.php?t=458107

Also, your write function only checks for a return code of -1. There might be more return codes, including zero, which are not detected in this way, and leave your program in a loop anyway.

I know this sounds pedantic, but from your fisrt post I got the idea you are trying to code as cleanly as possible, hence my two cents...

jlinkels

introuble 07-02-2006 12:26 AM

write() [ Write() ] will only be used on a socket. And yes, if the call fails, the program must exit.

Code:

No clean-up, no error messages, no action in case of a simple time-out.
#1. If I *really* want to, I can use atexit(). I see no reason to design my program so that if an error which must cause an exit occurs, the function this error occured in would return to it's caller, which would in turn return to it's caller etc. untill main would be reached and the return/exit call would be made there. However, except for "good practise" [which, I have to say, this time, I don't quite comprehend as I don't use memory-leak detecting software ..], I don't see a point in freeing buffers before an exit and not leaving it to the operating system. The data contained in those buffers isn't "sensitive" anyway.

#2. What do you mean no error messages?

Code:

perror("write");

And about the reference to that other thread .. look who's the thread starter :)


I'm always opened to suggestions. I've decided to look at code from other programs that use the same protocol as my app to see how things are done. My opinion is I have familiarity with C but what I deeply miss is the "practical" part. No book taught how things are done "in real life", this is the reason why this thread exists. [and the one you made reference to]

[p.s.: expect a thread asking about a "how-to" study the source of a large program :) ]

Cheers.

paulsm4 07-02-2006 01:31 AM

Hi - my :twocents:

1. Yes, I'd definitely encourage you to de-allocate all buffers before a *normal* exit, and *not* rely on the OS. It's just good discipline, if nothing else.

As far as an *abnormal* termination: that's different. No, I don't see any compelling reason to be anal as long as you're aborting the whole program.

2. As far as your original question, about concatenating a string:

a) I agree, global buffers probably aren't a great choice.

b) I also agree that "fprintf()" probably isn't a great choice, either (although tuxdev is right - there is absolutely *no* problem using fprintf with sockets under Linux).

c) So what's wrong with using three lines? That's fine; it's not at all unclear.

d) And what's wrong with doing an "sprintf()" (or the equivalent, for example "snprintf()") into a *stack* variable?

I honestly believe options c) and d) are equally clean, and perform equally well.

3. Finally (and what prompted me to write this) - a book recommendation:

Code Reading, Diomidis Spinellis
http://www.bookpool.com/ss?qs=code+reading

I honestly think you'll enjoy it!

Sincerely .. PSM

PS:
Was your "Write" wrapper inspired by Stevens?

jlinkels 07-02-2006 06:38 PM

Quote:

Originally Posted by introuble
#2. What do you mean no error messages?

Code:

perror("write");

Ok, I confused perror with that other command which writes to the system log. I don't call that (the other one) an error message to the user, but perror does the job.



Quote:

Originally Posted by introuble
And about the reference to that other thread .. look who's the thread starter :)
Cheers.

Isn't it a small world? :)


All times are GMT -5. The time now is 06:00 AM.