2

I have the following structure defined in C, and I want to send it using Berkeley Socket over a TCP connection between client and a server in Linux:

struct Argument{
int pid;
int length;
chat op;
char *data;
};

Since I have "char *data" which is a pointer than can be used for allocating a variable size of data in the local sending machine, I have to send this structure in two different times to the receiver side. The first time, I send only the fixed variables i.e. the first three variables. And then upon the reception, I allocate a buffer with a length size to receive the data part in the second time.

So my question is is there anyway to only send this structure one time to the other side with a variable data field size, not two times as what am I doing?

if (write(peer_fd, (struct Argument*) arg, sizeof (struct Argument)) < 0)
{
    close(peer_fd);
    return -1;
}

Thanks a lot.

IoT
  • 607
  • 1
  • 11
  • 23
  • If you know the size of `data` when allocating the structure you could use 0 length arrays. – imreal Mar 25 '14 at 00:01
  • @Nick Why use hack, if you have a completely legal solution? – this Mar 25 '14 at 00:02
  • Just throwing out there, the OP seems to want a single block. Besides they are perfectly legal where I live :) – imreal Mar 25 '14 at 00:07
  • @Nick The correct way to do that is to use flexible array member, 0 length arrays are an extension to some compilers, I doubt c standard has anything positive to say about them. – this Mar 25 '14 at 00:09
  • You're right, actually I meant flexible array members. My bad. – imreal Mar 25 '14 at 00:11

1 Answers1

1

Consider using scatter-gather read-write techniques.

readv writev

The wtitev allows you to write from multiple buffers (the fixed sized header and the char array) in a single call. You incur the cost of a single system call, and the sockets code inside the kernel assembles the data into a single buffer (if possible), and makes a single network call.

Ziffusion
  • 8,779
  • 4
  • 29
  • 57
  • I tried your way, but the problem in the receiver side ,the readv command doesn't return the length of the iov. You need to set it manually, so I returned back to original problem. – IoT Mar 25 '14 at 01:38
  • Right. But your problem is addressed to some extent. On the write side, you have only one system call and one network write (instead of 2 each). On the read side, you can do one of two things. Either read into a buffer that is sized to the upper bound of your array size - which results in a single read. Or make one read for the header, and the second for array - which is two system calls BUT a single network call. Either one is an improvement on the original. – Ziffusion Mar 25 '14 at 01:48
  • Can you please elaborate more regarding the reading part? Can you give me an example for making two read? Thanks. – IoT Mar 25 '14 at 02:24
  • You'll have to read the fixed data so that you can get the length of the variable data before you try reading it — unless you know there's an upper bound on the size of the variable data and you can preallocate enough space for the maximum possible size. If you have an upper bound, you can use `readv()`. If you don't have an upper bound, you have to use separate `read()` calls. – Jonathan Leffler Mar 25 '14 at 03:08
  • The 2 reads are similar to what you are doing now. First read gets you the fixed size header, which contains the length. The second read gets you the array (by which time you have allocated the right sized buffer). This is still 2 read system calls. But there was ONLY one network read. You don't have to use readv for this. Normal read will do. The write side would use writev though. – Ziffusion Mar 25 '14 at 03:14