Hi (sorry for my bad English), I'm trying to practice Linux to manipulate message queues in IPC. I have created a program that allows one process (child 1) to send the message in the queue, while the other process (child 2) reads that message. this message is defined as a structure composed of two strings (str1 and str2) and a type (long). The goal that I want to realize and read the two strings but the result is that the program in the reads only one. Thanks.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <time.h>
typedef struct{
long int type;
char str1[255];
char str2[255];
}msg;
void sender(int fd_msg){
msg message;
char *string1 = "Hello";
char *string2 = "World";
strcpy(message.str1,string1);
strcpy(message.str2,string2);
message.type = 1;
if(msgsnd(fd_msg,&message,strlen(message.str1)+1,0) == -1){
printf("Error sending message at message 1 queue %d --> %s\n",errno,strerror(errno));
return;
}
message.type = 2;
if(msgsnd(fd_msg,&message,strlen(message.str2)+1,0) == -1){
printf("Error sending message at message 2 queue %d --> %s\n",errno,strerror(errno));
return;
}
if(printf("Message sent at the queue: %s -- %s\n",message.str1,message.str2) < 0){
printf("Error printing sent messages %d --> %s\n",errno,strerror(errno));
msgctl(fd_msg,IPC_RMID,NULL);
return;
}
return;
}
void receiver(int fd_msg){
msg message;
char string1[255];
char string2[255];
sleep(1);
if(msgrcv(fd_msg,&message,sizeof(message)-sizeof(long int),1,0) == -1){
printf("error reiceiving message type 1 %d --> %s\n",errno,strerror(errno));
return;
}
if(msgrcv(fd_msg,&message,sizeof(message)-sizeof(long int),2 ,0) == -1){
printf("error reiceiving message type2 %d --> %s\n",errno,strerror(errno));
return;
}
if(printf("Message reiceved! : %s -- %s\n",message.str1,message.str2) < 0){
printf("Error printing received message %d --> %s\n",errno,strerror(errno));
msgctl(fd_msg,IPC_RMID,NULL);
return;
}
strcpy(string1,message.str1);
strcpy(string2,message.str2);
//printf("string2: %s\n",messaggio.str2);
return;
}
int main(int argc, char* argv[]){
int fd_msg = -1;
int key_msg = -1;
pid_t p1;
pid_t p2;
key_msg = ftok("../Example/in.txt",55);
if((fd_msg = msgget(key_msg,IPC_CREAT | 0770)) == -1){
printf("Error creation message queue %d --> %s\n",errno, strerror(errno));
return -1;
}
if((p1 = fork()) == 0){
//child 1 (writer)
sender(fd_msg);
exit(0);
}
waitpid(p1,NULL,0);
if((p2 = fork()) == 0){
//child 2 (reader)
receiver(fd_msg);
exit(0);
}
waitpid(p2,NULL,0);
msgctl(fd_msg,IPC_RMID,NULL);
return 0;
}
You should send only one message and a length of sizeof(message)-sizeof(long int)
just as you do for receiving the message. That's because str1
and str2
have fixed lengths of 255.
You want only one message (that sends the data for both strings in a single message).
As you have it, the "short" payload length that you [should] send is 255 + 5 + 1
and not 5 + 1 + 5 + 1
There are a number of ways to do this:
sizeof(msg)
str1
but short length of str2
str1
and str2
into a single buffer and [manually] concatenate/split the stringsExample #1:
Here is the corrected code using the full message size:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <time.h>
typedef struct {
long int type;
char str1[255];
char str2[255];
} msg;
void
sender(int fd_msg)
{
msg message;
char *string1 = "Hello";
char *string2 = "World";
strcpy(message.str1, string1);
strcpy(message.str2, string2);
size_t len = sizeof(message) - sizeof(long);
message.type = 1;
printf("Sending length %zu\n",len);
if (msgsnd(fd_msg, &message, len, 0) == -1) {
printf("Error sending message at message 1 queue %d --> %s\n", errno, strerror(errno));
return;
}
if (printf("Message sent at the queue: %s -- %s\n", message.str1, message.str2) < 0) {
printf("Error printing sent messages %d --> %s\n", errno, strerror(errno));
msgctl(fd_msg, IPC_RMID, NULL);
return;
}
return;
}
void
receiver(int fd_msg)
{
msg message;
char string1[255];
char string2[255];
sleep(1);
ssize_t len = msgrcv(fd_msg, &message, sizeof(message) - sizeof(long int), 1, 0);
if (len == -1) {
printf("error receiving message type 1 %d --> %s\n", errno, strerror(errno));
return;
}
printf("Received length: %zu\n",len);
if (printf("Message received! : %s -- %s\n", message.str1, message.str2) < 0) {
printf("Error printing received message %d --> %s\n", errno, strerror(errno));
msgctl(fd_msg, IPC_RMID, NULL);
return;
}
strcpy(string1, message.str1);
strcpy(string2, message.str2);
// printf("string2: %s\n",messaggio.str2);
return;
}
int
main(int argc, char *argv[])
{
int fd_msg = -1;
int key_msg = -1;
pid_t p1;
pid_t p2;
key_msg = ftok("../Example/in.txt", 55);
if ((fd_msg = msgget(key_msg, IPC_CREAT | 0770)) == -1) {
printf("Error creation message queue %d --> %s\n", errno, strerror(errno));
return -1;
}
if ((p1 = fork()) == 0) {
// child 1 (writer)
sender(fd_msg);
exit(0);
}
waitpid(p1, NULL, 0);
if ((p2 = fork()) == 0) {
// child 2 (reader)
receiver(fd_msg);
exit(0);
}
waitpid(p2, NULL, 0);
msgctl(fd_msg, IPC_RMID, NULL);
return 0;
}
Here is the program output:
Sending length 512
Message sent at the queue: Hello -- World
Received length: 512
Message received! : Hello -- World
Example #2:
Here is the program using a "short" length for str2
:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <time.h>
typedef struct {
long int type;
char str1[255];
char str2[255];
} msg;
void
sender(int fd_msg)
{
msg message;
char *string1 = "Hello";
char *string2 = "World";
strcpy(message.str1, string1);
strcpy(message.str2, string2);
size_t len = sizeof(message.str1) + strlen(message.str2) + 1;
message.type = 1;
printf("Sending length %zu\n",len);
if (msgsnd(fd_msg, &message, len, 0) == -1) {
printf("Error sending message at message 1 queue %d --> %s\n", errno, strerror(errno));
return;
}
if (printf("Message sent at the queue: %s -- %s\n", message.str1, message.str2) < 0) {
printf("Error printing sent messages %d --> %s\n", errno, strerror(errno));
msgctl(fd_msg, IPC_RMID, NULL);
return;
}
return;
}
void
receiver(int fd_msg)
{
msg message;
char string1[255];
char string2[255];
sleep(1);
ssize_t len = msgrcv(fd_msg, &message, sizeof(message) - sizeof(long int), 1, 0);
if (len == -1) {
printf("error receiving message type 1 %d --> %s\n", errno, strerror(errno));
return;
}
printf("Received length: %zu\n",len);
if (printf("Message received! : %s -- %s\n", message.str1, message.str2) < 0) {
printf("Error printing received message %d --> %s\n", errno, strerror(errno));
msgctl(fd_msg, IPC_RMID, NULL);
return;
}
strcpy(string1, message.str1);
strcpy(string2, message.str2);
// printf("string2: %s\n",messaggio.str2);
return;
}
int
main(int argc, char *argv[])
{
int fd_msg = -1;
int key_msg = -1;
pid_t p1;
pid_t p2;
key_msg = ftok("../Example/in.txt", 55);
if ((fd_msg = msgget(key_msg, IPC_CREAT | 0770)) == -1) {
printf("Error creation message queue %d --> %s\n", errno, strerror(errno));
return -1;
}
if ((p1 = fork()) == 0) {
// child 1 (writer)
sender(fd_msg);
exit(0);
}
waitpid(p1, NULL, 0);
if ((p2 = fork()) == 0) {
// child 2 (reader)
receiver(fd_msg);
exit(0);
}
waitpid(p2, NULL, 0);
msgctl(fd_msg, IPC_RMID, NULL);
return 0;
}
Here is the program output:
Sending length 261
Message sent at the queue: Hello -- World
Received length: 261
Message received! : Hello -- World
Example #3:
Using separate str1
and str2
forces us to send the full size for str1
even if the actual string length is less.
To send a single message that has both strings and sends only the length we need would require combining str1
and str2
into a single buffer (e.g. strs
). This requires that we concatenate the two strings into the buffer.
This also requires that the receiver recover the two separate strings.
Here is the code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <time.h>
typedef struct {
long int type;
char strs[512];
} msg;
void
sender(int fd_msg)
{
msg message;
char *string1 = "Hello";
char *string2 = "World";
char *cp = message.strs;
strcpy(cp, string1);
cp += strlen(cp) + 1;
strcpy(cp, string2);
cp += strlen(cp) + 1;
size_t len = cp - message.strs;
message.type = 1;
printf("Sending length %zu\n",len);
if (msgsnd(fd_msg, &message, len, 0) == -1) {
printf("Error sending message at message 1 queue %d --> %s\n", errno, strerror(errno));
return;
}
}
void
receiver(int fd_msg)
{
msg message;
char string1[255];
char string2[255];
sleep(1);
ssize_t len = msgrcv(fd_msg, &message, sizeof(message) - sizeof(long int), 1, 0);
if (len == -1) {
printf("error receiving message type 1 %d --> %s\n", errno, strerror(errno));
return;
}
printf("Received length: %zu\n",len);
char *cp = message.strs;
strcpy(string1, cp);
cp += strlen(cp) + 1;
strcpy(string2, cp);
cp += strlen(cp) + 1;
printf("string1: %s\n",string1);
printf("string2: %s\n",string2);
return;
}
int
main(int argc, char *argv[])
{
int fd_msg = -1;
int key_msg = -1;
pid_t p1;
pid_t p2;
key_msg = ftok("../Example/in.txt", 55);
if ((fd_msg = msgget(key_msg, IPC_CREAT | 0770)) == -1) {
printf("Error creation message queue %d --> %s\n", errno, strerror(errno));
return -1;
}
if ((p1 = fork()) == 0) {
// child 1 (writer)
sender(fd_msg);
exit(0);
}
waitpid(p1, NULL, 0);
if ((p2 = fork()) == 0) {
// child 2 (reader)
receiver(fd_msg);
exit(0);
}
waitpid(p2, NULL, 0);
msgctl(fd_msg, IPC_RMID, NULL);
return 0;
}
Here is the program output:
Sending length 12
Received length: 12
string1: Hello
string2: World
Example #4:
I'd probably do example #1 and send the full struct length.
Or, I'd use the combined buffer from example #3, but send two separate messages, one for each string:
Here is the code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <time.h>
typedef struct {
long int type;
char str[255];
} msg;
void
sendone(int fd_msg,int type,const char *str)
{
msg message;
strcpy(message.str, str);
size_t len = strlen(str) + 1;
message.type = type;
printf("Sending type %ld length %zu\n",message.type,len);
if (msgsnd(fd_msg, &message, len, 0) == -1) {
printf("Error sending message at message 1 queue %d --> %s\n", errno, strerror(errno));
return;
}
printf("Message sent at the queue: %s\n", message.str);
}
void
sender(int fd_msg)
{
char *string1 = "Hello";
char *string2 = "World";
sendone(fd_msg,2,string2);
sendone(fd_msg,1,string1);
return;
}
ssize_t
recvone(int fd_msg,msg *message)
{
int type = 0;
ssize_t len = msgrcv(fd_msg, message, sizeof(msg) - sizeof(long int), type, 0);
if (len == -1) {
printf("error receiving message %d --> %s\n", errno, strerror(errno));
return len;
}
printf("Received type %ld message of length: %zu\n",message->type,len);
printf("Message received! : %s\n",message->str);
return len;
}
void
receiver(int fd_msg)
{
msg message;
char strings[2][255];
sleep(1);
// deliberately receive messages in any order
for (int imsg = 1; imsg <= 2; ++imsg) {
recvone(fd_msg,&message);
strcpy(strings[message.type - 1],message.str);
}
for (int imsg = 1; imsg <= 2; ++imsg)
printf("receiver: string %d: %s\n",imsg,strings[imsg - 1]);
return;
}
int
main(int argc, char *argv[])
{
int fd_msg = -1;
int key_msg = -1;
pid_t p1;
pid_t p2;
key_msg = ftok("../Example/in.txt", 55);
if ((fd_msg = msgget(key_msg, IPC_CREAT | 0770)) == -1) {
printf("Error creation message queue %d --> %s\n", errno, strerror(errno));
return -1;
}
if ((p1 = fork()) == 0) {
// child 1 (writer)
sender(fd_msg);
exit(0);
}
waitpid(p1, NULL, 0);
if ((p2 = fork()) == 0) {
// child 2 (reader)
receiver(fd_msg);
exit(0);
}
waitpid(p2, NULL, 0);
msgctl(fd_msg, IPC_RMID, NULL);
return 0;
}
Here is the program output:
Sending type 2 length 6
Message sent at the queue: World
Sending type 1 length 6
Message sent at the queue: Hello
Received type 2 message of length: 6
Message received! : World
Received type 1 message of length: 6
Message received! : Hello
receiver: string 1: Hello
receiver: string 2: World