2
votes

I have seen a lot of answers that are related to my question, but I really cannot use it under my condition.

I am building a network module using socket programming with C language under Linux domain. I have to implement a function that could send a struct that consists of int, char, char * and some other structures (nested struct).

struct EnQuery
{
   char  type[6]; // insert, select , update , delete
   char * columns; //note here, it's an array of big, {name, age, sex, position, email}  not in string
   struct Values * values; //an array of values(another struct), {tom, 23, male, student, [email protected]}  is represented by the second struct values, not in string
   struct condition * enCondition; //  array of condition,  "name=tom and age>30" is represnted by the third struct condition
   short len;
   short rn; 
};

struct Values
{
    char * doc;
    char  key[2];
    char  s;
};

struct condition
{
     short k;              
     struct condition * children;
};

Above is the structure that I am trying to send. I am declaring the variables and sending over through socket using send() function.

How would I have to send char * through the socket? Or would there be a way to resize the char array length conveniently?

P.S I can't use external libraries

4
Just decide on the wire format you want to use and write code to convert to and from that wire format. Look at existing specification (BER, XML, JSON, etcetera) for ideas.David Schwartz
I cant use any external libraries..Yong Hee Lee
Your strcts has pointers, and that cannot be transmitted as they will not be valid at the receiving end -- you need to serialize and deserialize the data -- how you do that has a million good answers.Soren
Everything with a star (*) needs to be serialized, not only the chars. If you didn't have any pointers you could just send the struct as is (assuming receiver have the same endianness and memory padding etc).Soren
Don't use structs as network protocols. Use network protocols as network protocols. First define the protocol in octets, then write yourself an API to send and receive it.user207421

4 Answers

3
votes

How would I have to send char * through the socket?

Obviously, sending the pointer value isn't a useful thing to do, since the pointer wouldn't point to anything valid on the receiving computer.

So instead of sending the pointer, you have to send the data that it points to. A typical method for doing that would be to first send the number of bytes the pointer points to:

uint32_t sLen = strlen(doc)+1;  // +1 because I want to send the NUL byte also
uint32_t bigEndianSLen = htonl(sLen);
if (send(sock, &bigEndianSLen, sizeof(bigEndianSLen), 0) != sizeof(bigEndianSLen)) perror("send(1)");

.... and then follow by sending the bytes of the string:

if (send(sock, doc, sLen, 0) != sLen) perror("send(2)");

On the receiving side, you'd do the opposite: first receive the string's length:

uint32_t bigEndianSLen;
if (recv(sock, &bigEndianSLen, sizeof(bigEndianSLen), 0) != sizeof(bigEndianSLen)) perror("recv(1)");
uint32_t sLen = ntohl(bigEndianSLen);

... and then receive the string's data:

char * doc = malloc(sLen+1);
if (recv(sock, doc, sLen, 0) != sLen) perror("recv(2)");
doc[sLen] = '\0';  // paranoia:  make sure the string is terminated no matter what

Note that this example code is a bit naive, in that it doesn't handle correctly the case where send() or recv() return a value other than the byte-count that was passed in to them. Production-quality code would handle errors properly (e.g. by closing the connection), and would also handle properly the case where send() or recv() send/receive only transferred some of the bytes that were requested (by calling send()/recv() again later for the remaining unsent/unreceived bytes).

2
votes

You need to make a choice : either serialize the data structure in memory on the sending side using a "pack" function, send across the wire and deserialize using an unpack function (straightforward), or dynamically serialize/deserialize straight to the socket (better done afterwards as an optimization of the first version).

You can get some inspiration from this open source code for example: https://code.google.com/p/protobuf-c/

0
votes

define an enum with "type numbers". Using your example:

Tchar
Tstring
Tshort
Tint
TEnQuery
TValues
Tcondition
Tpop

Define a few flag bits that get or'ed with the type:

Tarray -- array of base type
Tvalues
Tstring,data for doc (inc EOS)
Tchar | Tarray,2,key data
Tchar,s value
Tpop

Now you have a byte stream that you process recursively with a state machine of sorts. You'll need recursive functions for export/import for all the above types. On import, the key thing is that type number is what you dispatch on

-3
votes

A struct is a data type available with the (ANSI) C language. I believe you are looking for the following functions to perform sending of the data within your struct.

  1. socket()
  2. read()
  3. write()

Keep in mind these are the bare minimum requirements for IPC (also referred to as signals), TCP/IP and/or UDP communications.

For a simple implementation of a client/server architecture (although thoroughly outdated these days) reference; client / server. You might serve better to focus your studies on peer to peer communication providing you with a more robust set of fail overs as each peer holds connection information for each other; see here:

peer to peer