Solved

Linux Sockets - Client / Server

Posted on 2004-04-17
20
441 Views
Last Modified: 2010-04-22
I'm trying to write a client/server program under linux. The protocol is similar to FTP (using TEXT commands and answers).

My problem the following:
I'm sending from the client:
1st write:  FILE file_name_1
2nd write: FILE file_name_2

but on the server's side they end up in a single packet, containing FILE file_name_1FILE file_name_2!

I've tried setting the TCP_NODELAY option on the socket, as well as usleep()ing between writes, but they don't work!  
Any ideas?
0
Comment
Question by:Dragon_Krome
  • 7
  • 5
  • 2
  • +3
20 Comments
 
LVL 10

Expert Comment

by:Mercantilum
Comment Utility
Did you fflush your descriptor after each write?
Have a look to http://www.informit.com/articles/article.asp?p=22086
( "Connecting to the server" )
0
 
LVL 5

Author Comment

by:Dragon_Krome
Comment Utility
I see in that article that they convert the standard socket descriptor into a FILE* by using fdopen.
From what I know, read/write are unbuffered, as opposed to fread/fwrite (where fflush should be used).
Or am I mistaking? Perhaps if I'd use recv/send instead of read/write ?
0
 
LVL 10

Expert Comment

by:Mercantilum
Comment Utility
The "symptoms" of your problem sound like a buffering problem.
Could you post the relevant part of your code?
0
 
LVL 5

Author Comment

by:Dragon_Krome
Comment Utility
This would be the relevant part.

for (parse_a_file_list...)
      {
                  snprintf(buf,sizeof(buf)-1,"FILE %s/%lu/%s",fis_scan->nume,
                                                                                    fis_scan->size,
                                                                                    fis_scan->desc);
                  write(serv_socket,buf,strlen(buf));
                  //usleep(100000);    // <---- sometimes this solves the problem
      }

I want each written() message to be read() individually....but they're in there togeter (FILE 1/343/asdsadFILE 2/3984/asdsadsa.... etc. ).

I've set TCP_NODELAY, IPTOS_LOWDELAY and even tried to set SO_SNDBUF to 0... none work. The usleep() method is working with a high interval, but it's not the way I want to do this...
0
 
LVL 10

Expert Comment

by:Mercantilum
Comment Utility
On server side, you "setsockopt" with TCP_NODELAY after the accept.
On client side did you do it as well after the connect?
0
 
LVL 5

Author Comment

by:Dragon_Krome
Comment Utility
I was setting TCP_NODELAY just after socket(). I've tried after accept/connect too, still the same... :((
0
 
LVL 10

Expert Comment

by:Mercantilum
Comment Utility
From Google groups:
> If I connect to another host, I create a socket. If I write
> n bytes to this socket one question arises:
>
> * Will the operating system send this block of data
>   imedeately to the other host or will it wait for
>   another m bytes until an internal buffer is filled ?
>
> If so, how can I change the size of this buffer ?
>
> Thanks in advance,

A write() on a socket might be buffered for a (very short) time
to get data from the next write() into the same transport-paket.
If no write() is called for this short time (normally something
around 100ms) a paket (which is not completely filled) will be
sent.
Generally the data of your write() will not be buffered until
enough data for maximum paketsize is available.
(http://groups.google.com/groups?q=g:thl3166708581d&dq=&hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=01bce453%246a5efdc0%24c48bca95%40samos_pc2)

Can you please try with fdopen and fflush, as it is fast to implement, to ensure that it is the problem.
0
 
LVL 5

Author Comment

by:Dragon_Krome
Comment Utility
I've replaced some of the code with fprintf and fflush and the data doesen't get sent anymore :( .  I'll have to look into this more carefully.
0
 
LVL 10

Expert Comment

by:Mercantilum
Comment Utility
It appears that the delay you commented in your program is exactlly the 100ms of the comment above.
Since your packets are very small, it is likely that the above comment applies.

Your code should look like

   FILE *fp;
   if ((fp = fdopen(serv_socket, "w")) == NULL) {  perror("Could not open file stream from file descriptor");   return;  }

   for (parse_a_file_list...)
   {
               snprintf(buf,sizeof(buf)-1,"FILE %s/%lu/%s",fis_scan->nume, fis_scan->size, fis_scan->desc);
               fprintf(fp, buf);
               fflush(fp);
     }
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 45

Expert Comment

by:sunnycoder
Comment Utility
IMHO you should be trying to modify your code to accept multiple commands rather than finding ways of flushing the socket ...

Combining several packets into one is a normal optimization carried out by most network stacks ... Your recepient should be capable of parsing and executing all the requests that it receives in any number of packets ...
This will need far less efforts, will not be platform dependent and will make your program robust ... while finding hacks for flushing the socket will need more efforts (as you might have realized by now) may be platform dependent and you may find yourself not being able to reproduce the effect in your school server
0
 
LVL 8

Expert Comment

by:da99rmd
Comment Utility
I vote for sonnycoders example just use delimiters to part the 2 commands, an example would be:
1st write:  FILE file_name_1
2nd write: FILE file_name_2

the packet will then be.
"%STARTC%FILE file_name_1%ENDC%%STARTC%FILE file_name_2%ENDC%"
in this way you can split out the commands from the packet.

For more helpful reading on making applikcation layer protocols use smtp protocol as base its easy and very good.
http://www.freesoft.org/CIE/RFC/821/index.htm

/Rob
0
 
LVL 10

Expert Comment

by:Mercantilum
Comment Utility
I vote for Dragon_krome, as he is the requester  (:o

The concatenation is a good suggestion, but DK may have good reasons to get 2 packets.
At least now that he has the two solutions he can choose :)
0
 
LVL 5

Author Comment

by:Dragon_Krome
Comment Utility
Guys...

I wanted a way to make this thing go away... :) I understand it's purpose, but I don't need it. I wanted to disable it,
because I was not aware at the time when I wrote my code, and adding a parser would be a pain in the a**. (I was close
to a deadline).

Mercantilum:  tried the fflush() part on a part of my code... the result: nothing was sent at all :(  dunno why.

I did this the ugly way, using usleeps()...
0
 
LVL 10

Expert Comment

by:Mercantilum
Comment Utility
You should have something like
   newsocket = accept (...);

this is the one to be used in fdopen - oh, by the way, please try with "r+" (not "w" as I mentioned before)

   if ((fp = fdopen(newsocket, "r+")) == NULL) {  perror("Could not open file stream from file descriptor");   return;  }

This should work.
0
 
LVL 8

Expert Comment

by:da99rmd
Comment Utility
I se your problem with the time issue.
But it can  be buffered on the recieving side to.
Try altering SO_RCVBUF to on the recieving side.
But dont make them to small because then the socket will stop sending, dnot know why thou.

/Rob
0
 
LVL 4

Expert Comment

by:NVRAM
Comment Utility
The FTP standard requires an EOL marker between commands for this reason.  

There are two simple solutions I see to your problem:
 1) essentially what da99rmd said - add a newline after each command (could be a null, or anything that will not occur in the command text),
 2) send a size word before each 'packet', like this (note that sockwrite() only handles null terminated strings, to pass in a length, just remove the 'strlen' line and make 'len' an argument)...  [I just typed that into the browser, it may not even compile, but you get the gist...]

       // Using hton() and ntoh() will acommodate big- and little-endian differences.  
       int sockwrite(int sock, const char buf[] ) {
           int len = strlen(buf);             // Might want to use 'hton()' to be platform independent...
           int rc1 = write( sock, &len, sizeof(len));
           if (rc1 != sizeof(len))
                return rc1;
           return write( sock, buf, strlen(buf));
       }

       int sockread( int sock, int& len, char buf[] ) {
           int rc1 = read( sock, &len, sizeof(len));               // Might want to use 'ntoh()' to be platform independent...
           if (rc1 != sizeof(len))
                return rc1;
           return read( sock, buf, len );
       }
0
 
LVL 45

Expert Comment

by:sunnycoder
Comment Utility
Hi GhostMod,

I recommend to PAQ the question ... I leave it upto you to decide whether to refund or not.
0
 
LVL 5

Accepted Solution

by:
Netminder earned 0 total points
Comment Utility
Closed, no points refunded.
Netminder
Site Admin
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Have you ever been frustrated by having to click seven times in order to retrieve a small bit of information from the web, always the same seven clicks, scrolling down and down until you reach your target? When you know the benefits of the command l…
The purpose of this article is to demonstrate how we can upgrade Python from version 2.7.6 to Python 2.7.10 on the Linux Mint operating system. I am using an Oracle Virtual Box where I have installed Linux Mint operating system version 17.2. Once yo…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now