sending an array of structs across a socket - c

What if I had a an array of struct. Is it possible for me to send an array of structs over a socket? The struct size will be updated continuously and at any time I would be able to print out the content of the structs. I hope this makes sense, my explanation might not be cleared. My syntax is definitely not correct for some areas, it's just a snippet of what I think it would look like. I just need some guidance.
This will send the array of structs acorss the socket.
void sendOpenMessage(int num0, int num1, int num2){
struct openMessage{
int num0;
int num1;
int num2
};
struct openMessage open[100];
int i = 0;
open[i].num0 = 1;
open[i].num1 = 2;
open[i].num2 = 3;
int length = sizeof(open);
if(send(socket, &open[i], length, 0) == -1){
fprintf(stderr, "Send() failed");
}else{
printf("Open message is being sent\n");
}
i++;
}
This will receive the struct and display the contents in a message
struct openMessage open[100];
if(recv(clnSocket, &open, sizeof(open), 0) < 0){
fprintf(stderr,"Recv() failed\n");
printf("Error code: %d\n", errno);
}
//Get size of the current struct
//Print out the messages from the structs that have messages?
void printStruct(struct openMessage open){
for(int i = 0; i < sizeof(the struct); i++){
printf("%d\n",open[i].num0);
printf("%d\n", open[i].num1);
printf("%d\n", open[i].num2);
}
}

First of all, you need to read up about byte ordering and serialisation.
Secondly, length is the size of the whole array, so when i is zero you send the whole array, when i is 1 you send all but the first element plus some garbage at the end, and so on.
Thirdly, when receiving you iterate across sizeof(the struct) members of the array. Don't you want to iterate across the whole array?
When you say the struct size will be updated continuously, do you mean the number of elements in the array? Your struct has a fixed size.
If you are sending variable quantities of data, i.e. if you want to send a piece of data that has one length at one time and another length at another time, or even if you want the number of elements in the array to update dynamically, then you MUST send that size across the socket, and send it before the data. Send the size first, read it first on the receiving end, and then the receiving end will know how much more data to read, and more importantly, where the data ends so that if there is more data later it doesn't all get mixed up.

Related

How can i Concatenate memory blocks

I need a requirement where in i need to Concatenate memory blocks
I'm sending my data from UDP as chunks of 100 bytes, and i have verified the transfer, but when I send a 800 bytes array as 8 chunks, and Concatenate them to an array I'm not able to retrieve data
im sending an int array of 200 elements which comes to 800 bytes and the first element is being incremented to check data
my simple logic goes like this
// allocate memory for main memory block
void* rcv_Data = malloc(800);
// allocate memory for chunk memory block
void* tempdata = malloc(100);
// read all 8 chunks
for (int ndx=0; ndx<8;ndx++)
{
Read_packet(skt,tempdata,100);
memmove((rcv_Data +(ndx*100)) ,tempdata, 100);
}
printf("data is %d\n",((int*)rcv_Data )[0]);
but my data being printed is 0 all time , but actual data is a incrementing number
my read function is as follows
int Read_packet(int CSPL_Socket, void *buf,int datalen)
{
int numb_bytes=0;
numb_bytes=read(CSPL_Socket, buf, datalen);
if(numb_bytes<0)
{
CSPL_SOK_ERROR(-6);
close(CSPL_Socket);
exit(1);
return -1;
}
else
{
//printf("Count %d\n",numb_bytes);
}
return 0;
}
i have just posted small portion of code , just not to make it too long and complicate, i need advice on whether this logic is correct or not

Stored data is not same which I can access in file read loop

I have to read a txt with data in it. I can read it and store the data, but I don't know why, some stored data is not good after the read method.
Here is my output:
I write out these data with exactly the same code, except that the first is inside the loop and the second is outside of the loop.
I store these data in their own struct arrays. So as you can see, my problem is that I can't access my data outside that loop. What could be wrong?
Here is the full code: https://pastebin.com/wzEJqcZG
And the test data: https://pastebin.com/L7J133mz
This is inside the file read loop:
printf("%c %i - ", sorok[i].futarkod, sorok[i].datum);
for(j=0;j<sorok[i].rendelesCount;j++) {
printf("%i%c", sorok[i].rendelesek[j].db, sorok[i].rendelesek[j].fajta);
}
printf("\n");
And this is outside of the file read loop:
for(i=0;i<5;i++) {
printf("%c %i - ", sorok[i].futarkod, sorok[i].datum);
for(j=0;j<sorok[i].rendelesCount;j++) {
printf("%i%c ", sorok[i].rendelesek[j].db, sorok[i].rendelesek[j].fajta);
}
printf("\n");
}
In the output the first two columns are good, just the text after the dash is not.
test.c:65:14: warning: 'sor' may not be used as an array element due to flexible array member
[-Wflexible-array-extensions]
sor sorok[32];
^
rendeles rendelesek[]; is a flexible array member meaning since it's at the end of the struct you can, in theory, allocate as much memory for the array as you like. However this means the size of any given sor will vary.
Each element of an array in C must be of a fixed size, going from one element to another is simply start-of-array-memory + (i * sizeof(element)). Since sor can be of different sizes it can't be put into an array.
You could use an array of pointers to sor, or you can change sor to contain a pointer to rendeles **rendelesek;. Or both, getting used to working with pointers is good.
The real problem is sor.rendelesek is never allocated. Whichever you choose, you still have to allocate memory to sor.rendelesek else you're writing into someone else's memory. As a flexible array member, you have to use a pointer array and allocate sufficient memory as part of sor.
typedef struct {
char futarkod;
int datum;
int rendelesCount;
rendeles rendelesek[];
} sor;
sor *sorok[32];
for( size_t i = 0; i < 32; i++) {
sorok[i] = malloc(sizeof(sor) + (sizeof(rendeles) * 32));
}
Or you can use a rendelesek ** instead and allocate that directly. Combining both is probably the best option.
typedef struct {
char futarkod;
int datum;
int rendelesCount;
rendeles *rendelesek;
} sor;
sor *new_sor(const size_t num_rendeles) {
sor *new = malloc(sizeof(sor));
new->rendelesek = malloc(sizeof(rendeles) * num_rendeles);
return new;
}
int main()
{
sor *sorok[32];
for( size_t i = 0; i < 32; i++) {
sorok[i] = new_sor(32);
}
Reading inputs into statically allocated structures like this is risky and wasteful because you have to allocate what you think is the most possible elements. It's very easy to allocate way too much or not enough. Instead they should be dynamically allocated as needed, but that's another thing.

Moving array of smaller structs into array of larger structs in C

Today I was working on a problem of moving an array of smaller structs directly into an array of larger structs (arrayNew) (essentially upgrading the smaller structs to store more information). The smaller structs needed to be read from a HDD in one single read operation into the array of new 'upgraded' larger structs, a function would be called to do the 'upgrading'. Also all the new fields in the structs that were read from the hard drive would be set to '0'.
Other more simple solutions that I tried were:
Creating a local array of the old structures (arrayOld), loading the structures from the HDD into it then simply looping through the empty array of the new structures (arrayNew) and manually moving each structs contents from arrayOld into arrayNew. (e.g. arrayNew[i].x = arrayOld[i].x; )
The problem with this is that in my case the arrays I was working with were very large and too large for the stack ( about 1mb for each array) causing a segmentation fault the instant the upgrading function was called.
Another viable solution was to create a dynamic array of the old structures (arrayDy) and load the old structures into arrayDy and then again manually moving each structs contents from arrayDy into arrayNew. (e.g. arrayNew[i].y = arrayDy[i].y; ) This addressed the issue of running out of stack memory.
After implementing the second solution. I decided to experiment and develop a solution that uses no dynamically allocated memory and loads the array of old structures from the HHD directly into the larger array of larger structs arrayNew in one read operation and manipulate the contents of arrayNew in memory to pad out the missing values that are there due to the array being bigger.
I will post my solution below in a scaled down version of what I implemented, using the following structs for my example:
typedef struct INNER_STRUCT_ {
int i_item1;
int i_item2;
char i_item3;
} INNER_STRUCT;
typedef struct SMALL_STRUCT_ {
int item1;
char item2;
INNER_STRUCT item3;
} SMALL_STRUCT;
typedef struct BIG_STRUCT_ {
int item1;
char item2;
INNER_STRUCT item3;
INNER_STRUCT item4;
} BIG_STRUCT;
Yes, this is possible - you can use union for that. C99 standard makes a special guarantee that can be used to implement your requirement:
6.5.2.3-5: One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the complete type of the union is visible.
Your structA_ and structB_ do share a common initial sequence, so creating a union and accessing the structs through it would do the trick:
union {
structA a;
structB b;
} u;
memset(&u.b, 0, sizeof(structB)); // Zero out the bigger structB
loadFromHdd(&u.a); // Load structA part into the union
// At this point, u.b is valid, with its structA portion filled in
// and structB part zeroed out.
Note that you cannot do it to an array (unless, of course, you make an array of unions). Each structA needs to be loaded individually into the union, from which it could then be read as structB.
The method I propose and used as a solution basically loads the smaller structs for the HDD ( a file in this case) into the array of new larger structs and then rearranges the block of memory so that each field can be accessed properly. The code to illustrate this is below, and is an mcve.
#include <stdio.h>
#include <string.h>
typedef struct INNER_STRUCT_ {
int i_item1;
int i_item2;
char i_item3;
} INNER_STRUCT;
typedef struct SMALL_STRUCT_ {
int item1;
char item2;
INNER_STRUCT item3;
} SMALL_STRUCT;
typedef struct BIG_STRUCT_ {
int item1;
char item2;
INNER_STRUCT item3;
INNER_STRUCT item4;
/*
Note that the big struct is exactly the same as the small
struct with one extra field - Key to this method working
is the fact that the extension to the struct is appended
at the end, in an array of the structs will be placed one
after the other in memory with no gaps*/
} BIG_STRUCT;
void printSmallStruct (SMALL_STRUCT *inStruct, int count) {
// Print everything inside given small struct
printf("\n\n Small struct %d, item1: %d \n",count,inStruct->item1);
printf(" Small struct %d, item2: %c \n",count,inStruct->item2);
printf(" Small struct %d, item3.i_item1: %d \n",count,inStruct->item3.i_item1);
printf(" Small struct %d, item3.i_item2: %d \n",count,inStruct->item3.i_item2);
printf(" Small struct %d, item3.i_item3: %c \n",count,inStruct->item3.i_item3);
}
void printBigStruct (BIG_STRUCT *inStruct, int count) {
// Print everything inside given big struct
printf("\n\n Big struct %d, item1: %d \n",count,inStruct->item1);
printf(" Big struct %d, item2: %c \n",count,inStruct->item2);
printf(" Big struct %d, item3.i_item1: %d \n",count,inStruct->item3.i_item1);
printf(" Big struct %d, item3.i_item2: %d \n",count,inStruct->item3.i_item2);
printf(" Big struct %d, item3.i_item3: %c \n",count,inStruct->item3.i_item3);
printf(" Big struct %d, item4.i_item1: %d \n",count,inStruct->item4.i_item1);
printf(" Big struct %d, item4.i_item1: %d \n",count,inStruct->item4.i_item2);
printf(" Big struct %d, item4.i_item1: %c \n",count,inStruct->item4.i_item3);
}
int main() {
SMALL_STRUCT smallStructArray[5]; // The array of small structs that we will write to a file then read
BIG_STRUCT loadedBigStructArray[5]; // The large array of structs that we will read the data from the file into
int i; // Counter that we will use
FILE *pfile; // pointer to our file stream
void *secondary_ptr; // void pointer that we will use to 'chop' memory into the size we want
/* Fill the array of structs (smallStructArray) */
for (i = 0; i < 5; i++) {
/* We fill each field with different data do we can ID that the right data is in the right fields */
smallStructArray[i].item1 = 111;
smallStructArray[i].item2 = 'S';
INNER_STRUCT* temp = &smallStructArray[i].item3;
temp->i_item1 = 777;
temp->i_item2 = 999;
temp->i_item3 = 'I';
}
/* Write the contents of smallStructArray to binary file then display it */
pfile = fopen("test.dat","wb");
if (pfile!=NULL){
for (i = 0; i < 5; i++) {
fwrite(&smallStructArray[i],sizeof(SMALL_STRUCT),1,pfile);
}
fclose(pfile);
}
else{
printf("Unable to open file!");
return 1;
}
for (i = 0; i < 5; i++) {
printSmallStruct(&smallStructArray[i],i);
}
/* Clear array of big structs using memset */
memset(&loadedBigStructArray[0],0,sizeof(loadedBigStructArray));
/* Here we read from the smallStructArray that was aved to file into the loadedBigStructArray */
pfile = fopen("test.dat","rb");
if (pfile !=NULL){
/*
He we pass fread the following: size_t fread(void *args1, size_t args2, size_t args3, FILE *args4)
args1 - a pointer to the beginning of a block of memory, in our case the beginning of the
array loadedBigStructArray.
args2 - the size of the ammout of bytes we wish to read, in our case the size of a SMALL_STRUCT,
the size one of the elments in the array saved to the file.
args3 - the ammount of elements to read, in our case five (which is the number of elements the
array saved to the file has.
args4 - a pointer to a FILE that specifies our input stream.
Essentially what fread will do here is read a block of bytes the size of the array we saved to
the file (smallStructArray) into the array in memory loadedBigStructArray from the
beggining of loadedBigStructArray. Fig 1 illustrates what this will look like in memory.
*/
fread(&loadedBigStructArray,sizeof(SMALL_STRUCT),5,pfile);
fclose(pfile);
}
else{
printf("Unable to open file!");
return 1;
}
/*
Due to the way the array on the file has been read into the array in memory, if we try
to access the data in loadedBigStructArray only the first 5 values will be valid, due to
the memory not being in the order we want. We need to re-arrange the data in loadedBigStructArray
*/
/*
Here we use a void pointer to point to the beggining of the loadedBigStructArray.
we will use this pointer to 'chop' the data loadedBigStructArray into SMALL_STRUCT
sized 'chunks' we can read from.
Due to the way pointers and arrays work in C we can cast the void pointer to any type we want
and get a chunk of memory that size begginnig from the pointer and its off set.
E.g. : int temp = ((int *)void_ptr)[i];
This example above will give us an integer 'temp' that was taken from memory beggining from position
void_ptr in memory and its offset i. ((int *)void_ptr) casts the pointer to type int and [i] dereferances
the pointer to location i.
*/
secondary_ptr = &loadedBigStructArray;
/*
Not we are going through the array backwards so that we can rearange the data with out overwriting
data in a location that has data which we havent moved yet. As the bottom end of the loadedBigStructArray
is essentially empty we can shift data down that way.
*/
for (i = 5; i > -1; i=i-1) {
SMALL_STRUCT temp = ((SMALL_STRUCT *)secondary_ptr)[i]; // dereference pointer to SMALL_STRUCT [i] inside loadedBigStructArray call it 'temp'
/*
Now that we have dereferenced a pointer a given SMALL_STRUCT inside loadedBigStructArray called 'temp'
we can use temp to move the data inside temp to its corresponding position in loadedBigStructArray
which rearragnes the data.
*/
loadedBigStructArray[i].item1 = temp.item1;
loadedBigStructArray[i].item2 = temp.item2;
loadedBigStructArray[i].item3.i_item1 = temp.item3.i_item1;
loadedBigStructArray[i].item3.i_item2 = temp.item3.i_item2;
loadedBigStructArray[i].item3.i_item3 = temp.item3.i_item3;
/* We then fill the new field to be blank */
loadedBigStructArray[i].item4.i_item1 = 0;
loadedBigStructArray[i].item4.i_item2 = 0;
loadedBigStructArray[i].item4.i_item3 = '0';
}
/* Print our new structures */
for (i = 0; i < 5; i++) {
printBigStruct(&loadedBigStructArray[i],i);
}
return 0;
}
Visualization of technique:
When fread does the single read operation of the array saved on disk into the array in memory due to it being smaller it will take up the first potion of the array in memory but the 'bottom' section could be anything, if we try to access the data in the new array with the current handles we have on the data we will either get inaccurate information or a bad piece of memory. We have to rearrange this data before we can use any of our handles on the structs in the array.

Write "complex" structures on a FIFO

I'm working a sort of "restaurant" implementation in C with client-server.
I am trying to send the following structure through a FIFO:
typedef struct {
int numtable; //table number to send answer
char timestamp[20]; //simple timestamp
int order[MENUSZ]; //array of int with dish IDs
} request;
About this struct, I basically send to the server the table number, to "build" the client FIFO name through a template, a timestamp, and order is a simple array filled with randomly chosen integers to "create" a sort of random menu request.
With this setup I didn't have problems, using
write(server_fd, &request, sizeof(request))
I had problems when I wanted to transform the array order[MENUSZ] in a pointer, to make a dynamic array, like this:
typedef struct {
int numtable;
char timestamp[20];
int *order;
} request;
After changing the struct, I used the malloc function to allocate enough space for the array:
request->order = malloc(sizeof(int)*numclients+1);
The array is fullfilled correctly, but for some reason the server can't read from the FIFO after I added this pointer, by doing
read(server_fd, &request, sizeof(request));
I can't figure out why it doesn't work with this pointer. Am I doing something wrong?
The array is fullfilled correctly, but for some reason the server can't read from the FIFO after I added this pointer, by doing
read(server_fd, &request, sizeof(request));
You are transferring your structure, which includes a pointer, and the value of the pointer will be transferred correctly, but it will not point to a valid address in the destination process, neither will there be memory allocated where the pointer points to.
Hence, you need to transfer the array separately and recreate the pointer in the destination process, something like:
read(server_fd, &request, sizeof(request));
/* allocate memory for request->order in the reader process */
request->order = malloc(sizeof(int)*numclients+1);
read(server_fd, request->order, sizeof(int)*numclients+1);
A yet better solution would be to also transfer the size of the array inside your structure.
On the sending side, you then need to send both, the structure and the array contents, something like
write(server_fd, &request, sizeof(request))
write(server_fd, request->order, sizeof(int)*numclients+1));
It is because sizeof(request) no longer tells you the size of the combined structure. Try this
typedef struct {
int numtable;
char timestamp[20];
int order[1];
} request;
When you have a new request
int reqsize = sizeof(request) + sizeof(int) * numclients;
request* req = malloc(reqsize);
This allows you to use req->order[1] to req->order[numclients - 1]. When you send it, use
write(server_fd, reqsize, sizeof(int))
write(server_fd, req, reqsize)
When reading
read(server_fd, &reqsize, sizeof(int))
Then allocate the request before reading
request* req = malloc(reqsize)
read(server_fd, req, reqsize)
This technique uses "the chumminess of C" http://c-faq.com/struct/structhack.html, which, as far as I know, works on all implementations of C.

TCP socket programming between two 64bit machines

I am trying to implemante a client- server program communication using TCP socket programming in C.
It is between between two 64bit machines with linux OS installed.
I want to transfer a c-struct between the two processes.
For this I try used a pack - unpack() functioanlity.
please consider the following code snipt
/*---------------------------------------------------------
on the sending side I have:
---------------------------------------------------------*/
struct packet {
int64_t x;
int64_t y;
int64_t q[maxSize];
} __attribute__((packed));
int main(void)
{
// build packet
struct packet pkt;
pkt.x = htonl(324);
pkt.y = htonl(654);
int i;
for(i = 0; i< maxSize; i++){
pkt.q[i] = i; **// I also try pkt.q[i] = htonl(i);**
}
// and then do the send
}
/*-----------------------------------------------------------------------------
in the receiving side:
-----------------------------------------------------------------------------*/
struct packet {
int64_t x;
int64_t y;
int64_t q[maxSize];
} __attribute__((packed));
static void decodePacket (uint8_t *recv_data, size_t recv_len)
{
// checking size
if (recv_len < sizeof(struct packet)) {
fprintf(stderr, "received too little!");
return;
}
struct packet *recv_packet = (struct packet *)recv_data;
int64_t x = ntohl(recv_packet->x);
int64_t y = ntohl(recv_packet->y);
int i;
printf("Decoded: x=%"PRIu8" y=%"PRIu32"\n", x, y);
for(i=0;i<maxSize;i++){
**//int64_t res = ntohl(recv_packet->q[i]); I also try to print res**
printf("%"PRIu32"\n" , recv_packet->q[i]);
}
}
int main(int argc, char *argv[]){
// receive the data and try to call decodePacket()
int8_t *recv_data = (int8_t *)&buf; //buf is the data received
size_t recv_len = sizeof(buf);
**decode_packet(recv_data, recv_len);**
}
//-----------------------------------------------------------------------------
Now the problem is that I am receiving the value of x and y in the struct correctly,
but for the array q in the struct I am receiving a strange number, possible a memory grabage value, (I try to use memset() filling the array by zeros before receiving a data from the other side in which case the value of all zeros is received )
I don't understand why I am not receiving the correct value for the array in struct.
Please Note that I try with and with out htonl() while filling the array before putting in struct,
and on the other side: with and with out ntohl() while decoding the array from struct
Any help will be appreciated,
size_t recv_len = sizeof(buf);
decode_packet(recv_data, recv_len);
This piece of code ensures the wrong size is passed to decode_packet. So when decode_packet goes on to check recv_len < sizeof(struct packet), that test is meaningless - it will always pass, no matter how many bytes were received.
You need to fetch the size from the value returned by the recv call. My best guess is that indeed you're receiving fewer bytes than you're expecting.
While sending and receiving structs is quite convenient, it's often an exercise in futility. Manually serializing data or using some explicit mechanisms is probably the way to go.
You didn't show us the send and recv part, which is more likely to be wrong. My guess is you're receiving first items in the array correctly and they "become" garbage at some point, is it right?
Well, #cnicutar is correct, but let me extend it a little bit...
First of all, when you call send you have to examine the return value and see if all bytes have been transmitted. If your structure is large (for example larger than underlying socket buffer) you'll need more than one call to transmit the whole structure. Same with recv, don't expect you will get the whole message in one recv call, don't expect every recv will receive the same amount of data that was sent by corresponding send call. Always check how many bytes have been received and call recv again if necessary (pointing to the right place in incoming buffer and reducing number of bytes to receive).
So what is probably happening, you don't receive enough data (maybe you don't even transmit all of it) and only beginning of your incoming buffer is being filled. Therefore, the rest of the structure is garbage or (when you call memset) stays initialised with zeros.
Also note both send and recv return ssize_t rather than size_t as negative values are possible (to indicate errors).

Resources