2

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

12
  • 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. Commented Oct 14, 2015 at 0:11
  • I cant use any external libraries.. Commented Oct 14, 2015 at 0:12
  • 1
    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. Commented Oct 14, 2015 at 0:14
  • 1
    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). Commented Oct 14, 2015 at 0:18
  • 2
    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. Commented Oct 14, 2015 at 0:25

4 Answers 4

3

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).

Sign up to request clarification or add additional context in comments.

9 Comments

Would this work on char as well? How would I have to cast this ?
char is not a pointer, so you can send a char directly, similarly to how you send an int (actually even easier than an int, since a char is only 1 byte you do not need to worry about endian-conversion issues for a char). E.g. char s = 'J'; send(sock, &s, 1, 0);
would you give me an example like above for char as well? Thank you in advance
I am trying to implement this, but since you have only specified an example with only one element, how would I add another? let say, send key[2] followed by doc? A specific example would be much appreciated and would contribute in a lot of help. Thank you very much
I am having trouble sending two elements at the moment.. If you could please help me with this, I would be appreciated
|
2

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/

4 Comments

would you be able to make some example with the specified struct? Thanks in advance
How about trying to write a very simple version of pack that copies only the fixed length items into a char[], and then extend that with code to copy an array of condition. Once you can do that you can use similar code to add a char* to the end of the char[], so now you can handle a Values struct. then, extend that code to handle an array of Values, and finally you have all the tools to do an EnQuery struct. By starting small, and debugging as you go, you can figure out how to do the big task.
Serializing directly to the socket is hardly an optimization -- it makes performance much worse.
This dates me unfortunately. The last time I wrote directly to a socket was when 10 Base-T was first coming on line and wasn't yet prevalent.
0

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
Now output the type number. Follow it by the actual data. For example, to output a Values struct:
Tvalues
Tstring,data for doc (inc EOS)
Tchar | Tarray,2,key data
Tchar,s value
Tpop
Any aggregate (e.g. struct) does an implied "Tpush" that is paired with the 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

Comments

-3

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.