[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 476
  • Last Modified:

Linux Sockets - Client / Server

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
Dragon_Krome
Asked:
Dragon_Krome
  • 7
  • 5
  • 2
  • +3
1 Solution
 
MercantilumCommented:
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
 
Dragon_KromeAuthor Commented:
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
 
MercantilumCommented:
The "symptoms" of your problem sound like a buffering problem.
Could you post the relevant part of your code?
0
Configuration Guide and Best Practices

Read the guide to learn how to orchestrate Data ONTAP, create application-consistent backups and enable fast recovery from NetApp storage snapshots. Version 9.5 also contains performance and scalability enhancements to meet the needs of the largest enterprise environments.

 
Dragon_KromeAuthor Commented:
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
 
MercantilumCommented:
On server side, you "setsockopt" with TCP_NODELAY after the accept.
On client side did you do it as well after the connect?
0
 
Dragon_KromeAuthor Commented:
I was setting TCP_NODELAY just after socket(). I've tried after accept/connect too, still the same... :((
0
 
MercantilumCommented:
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
 
Dragon_KromeAuthor Commented:
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
 
MercantilumCommented:
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
 
sunnycoderCommented:
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
 
da99rmdCommented:
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
 
MercantilumCommented:
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
 
Dragon_KromeAuthor Commented:
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
 
MercantilumCommented:
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
 
da99rmdCommented:
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
 
NVRAMCommented:
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
 
sunnycoderCommented:
Hi GhostMod,

I recommend to PAQ the question ... I leave it upto you to decide whether to refund or not.
0
 
NetminderCommented:
Closed, no points refunded.
Netminder
Site Admin
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

  • 7
  • 5
  • 2
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now