I've been working on a project and one of the tasks that I have to do is passing the string received from another process through a pipe to yet another process but this time I have to use a message queue.
I've managed to learn how msgqueue works and made a simple working program but, the thing is, it works when receiving a string from stdin through fgets.
My question is:
Can I pass a string that is already saved in other variable (for example
char s[20] = "message test"; ) to the msgqueues mtext?
My simple program looks like that:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>
struct msgbuf {
long mtype;
char string[20];
};
struct msgbuf mbuf;
int open_queue( key_t keyval ) {
int qid;
if((qid = msgget( keyval, IPC_CREAT | 0660 )) == -1)
return(-1);
return(qid);
}
int send_message( int qid){
int result, size;
size = sizeof mbuf.string;
if((result = msgsnd( qid, &mbuf, size, 0)) == -1)
return(-1);
return(result);
}
int remove_queue( int qid ){
if( msgctl( qid, IPC_RMID, 0) == -1)
return(-1);
return(0);
}
int read_message( int qid, long type){
int result, size;
size = sizeof mbuf.string;
if((result = msgrcv( qid, &mbuf, size, type, 0)) == -1)
return(-1);
return(result);
}
int main(void){
int qid;
key_t msgkey;
msgkey = ftok(".", 'm');
if(( qid = open_queue( msgkey)) == -1) {
perror("openErr");
exit(1);
}
mbuf.mtype = 1;
fgets(mbuf.string, sizeof mbuf.string, stdin);
if((send_message( qid)) == -1) {
perror("sendErr");
exit(1);
}
mbuf.mtype = 1;
if((read_message(qid, mbuf.mtype))== -1){
perror("recERR");
exit(1);
}
printf("Queue: %s\n", mbuf.string);
remove_queue(qid);
return 0;
}
Your code uses fgets() to fill the buffer mbuf.string with input read from stdin. You can instead use something like strcpy(mbuf.string, "message test") where you can pass in a variable or use a hard coded string.
I recommend using the POSIX message queue API as the System V API is deprecated.
Related
I am trying to run two processes which are basically sending and receiving messages using message queue(SYS V). While I can run two process on same terminal tab by keeping my receiver in background
./receiver &
and sender in the foreground.
./sender
which is working fine but causing all my prints from sender & receiver display on same tab.
If I try to run receiver on one terminal tab and sender on other terminal-tab, the processes are not working correctly, they fail to identify message queue exist on the system.
I am not sure if its the terminal issue, or my program issue, I am using MobaXterm terminal.
Added code below, Am I missing w.r.t running processes on two different terminals I would like to know.
receiver.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define PATH "/tmp/CMN_KEY"
struct message_text {
int qid;
char buf [200];
};
struct message {
long message_type;
struct message_text message_text;
};
int main (int argc, char **argv)
{
key_t key;
int qid;
struct message message;
if ((key = ftok (PATH,'Z')) == -1) {
printf ("ftok");
exit (1);
}
if ((qid = msgget (key, IPC_CREAT | 0660)) == -1) {
printf ("msgget");
exit (1);
}
printf ("Receiver: Waiting for MSG!\n");
while (1) {
// read an incoming message
if (msgrcv (qid, &message, sizeof (struct message_text), 0, 0) == -1) {
printf ("msgrcv");
exit (1);
}
printf ("Receiver: MSG Received.\n");
// message from sender
int length = strlen (message.message_text.buf);
char buf [20];
sprintf (buf, " %d", length);
strcat (message.message_text.buf, buf);
int client_qid = message.message_text.qid;
message.message_text.qid = qid;
// send reply message to Sender
if (msgsnd (client_qid, &message, sizeof (struct message_text), 0) == -1) {
printf ("msgget");
exit (1);
}
printf ("Receiver: Response sent to Sender .\n");
}
}
sender.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define PATH "/tmp/CMN_KEY"
struct message_text {
int qid;
char buf [200];
};
struct message {
long message_type;
struct message_text message_text;
};
int main (int argc, char **argv)
{
key_t key;
int sender_qid, myqid;
struct message my_message, return_message;
// queue for receiving messages from receiver
if ((myqid = msgget (IPC_PRIVATE, 0660)) == -1) {
printf ("msgget: myqid");
exit (1);
}
printf("Sender created q with ID: %d\n" , myqid);
if ((key = ftok (PATH,'Z')) == -1) {
printf ("ftok");
exit (1);
}
if ((sender_qid = msgget (key, 0)) == -1) {
printf ("msgget: sender_qid");
exit (1);
}
my_message.message_type = 1;
my_message.message_text.qid = myqid;
printf ("Input a message: ");
while (fgets (my_message.message_text.buf, 198, stdin)) {
int length = strlen (my_message.message_text.buf);
if (my_message.message_text.buf [length - 1] == '\n')
my_message.message_text.buf [length - 1] = '\0';
// send message to Receiver
if (msgsnd (sender_qid, &my_message, sizeof (struct message_text), 0) == -1) {
printf ("client: msgsnd");
exit (1);
}
// read response from Receiver
if (msgrcv (myqid, &return_message, sizeof (struct message_text), 0, 0) == -1) {
printf ("client: msgrcv");
exit (1);
}
// Return message from Receiver
printf ("Return Message From Receiver: %s\n\n", return_message.message_text.buf);
printf ("type a one more message: ");
}
// remove message queue
if (msgctl (myqid, IPC_RMID, NULL) == -1) {
printf ("client: msgctl");
exit (1);
}
return
}
I have written two programs one to send message using msgsnd and other to receive with msgrcv. I have been using these functions for quite a while, but I can't figure out "stack smashing detected" error in receiving file. In that file I try to copy one part of file to one char array and second part into second array. I get stack smashing detected after receiving program completion if msgrcv is ever called in a file. At the end of a file I call printf function to print two arrays. From my point arr1 and arr2 should contain complete message, while only arr1 contains message and arr2 is empty. But the biggest problem is stack smashing detected error. I place code for two files below:
Sending file:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/sem.h>
#include <sys/msg.h>
#include <stdint.h>
typedef struct message {
long type;
char text[128];
} message;
int main (int argc, char **argv) {
if (argc == 3 && strcmp (argv [1], "-m") == 0) {
key_t key = (key_t) atoi (argv[2]);
message msg;
int message_queue_id = msgget (key, IPC_CREAT | 0666);
int semaphore_set_id = semget (key, 1, IPC_CREAT | 0666);
struct semid_ds buf;
struct sembuf sb;
long long buf_address = (long long)&buf;
long long sb_address = (long long)&sb;
// sending message
msg.type = 6;
memset (msg.text, 0, 128);
printf ("%p %p\n", (void*)&buf, (void*)&sb);
sprintf (msg.text, "%lld %lld", buf_address, sb_address);
printf ("msg: %s\n", msg.text);
void* ptr = (void*)buf_address;
printf ("ptr = %p\n", ptr);
msgsnd(message_queue_id, (struct msgbuf*)&msg, sizeof (msg) - 4, 0);
sleep (1000);
}
}
Receiving file (without headers):
typedef struct message {
long type;
char text[128];
} message;
int main (int argc, char **argv) {
if (argc == 3 && strcmp (argv [1], "-m") == 0) {
key_t key = (key_t) atoi (argv[2]);
int message_queue_id = msgget (key, IPC_CREAT | 0666);;
int semaphore_set_id = semget (key, 1, IPC_CREAT | 0666);
message msg;
struct semid_ds buf;
struct sembuf sb;
msgrcv (message_queue_id, (struct msgbuf*)&msg, sizeof(msg) - 4, 6, IPC_NOWAIT);
printf ("msg = %s\n", msg.text);
char arr1[32] = "\0", arr2[32] = "\0";
int i = 0;
while (msg.text[i] != ' ') {
arr1[i] = msg.text[i];
i++;
}
i++;
while (msg.text[i]) {
arr2[i] = msg.text[i];
i++;
}
printf ("arr1 = %s, arr2 = %s\n", arr1, arr2);
printf ("sizeof(long) = %d\n", (int)sizeof(long));
}
}
msgrcv (message_queue_id, (struct msgbuf*)&msg, sizeof(msg) - 4, 6, IPC_NOWAIT);
The third parameter to msgrcv should be the size of the buffer stored in the message structure. When doing the calculation sizeof(msg) - 4, you seem to be assuming that the size of long is always 4, which is incorrect. Instead, you should simply use sizeof(msg.text).
You also have the same error in the sender. Because the size of long in 64-bit linux is 8 bytes and not 4, your code will write past the end of the msg variable, causing a buffer overflow.
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
C programming print a certain amount of bytes to screen
I would like to read partSize amount of bytes from one file, which can be of any type, and print that same exact amount that was read to a new file which already exists. The program I wrote seems to write less than it is suppose to and gives a segmentation fault.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#define PERMS 0777
#include <errno.h>
int main()
{
int createDescriptor;
int openDescriptorOriginal;
int closeCreateDescriptor;
char fileNameOriginal[15]="picture.jpg";
//char fileNameOriginal[15]="myFile.txt";
//char fileNameNew[15]="NEWFILE.txt";
char fileName[15]="NEWFILE.jpg";
int parts;
int partSize;
parts=2;
int bytesRemaining;
int partNumber;
char BUFFER[512];
int readDescriptor;
int openDescriptor;
if ((openDescriptorOriginal = open(fileNameOriginal, O_RDONLY )) == -1)
{
printf("Error opening %s", fileNameOriginal);
exit(EXIT_FAILURE);
}
struct stat buf;
int r = fstat(openDescriptorOriginal, &buf);
if(r)
{
fprintf(stderr, "error: fstat: %s\n",(char *)strerror(errno));
exit(1);
}
int originalFileSize=buf.st_size;
printf("The file is %d Bytes large.\n",originalFileSize);
partSize=((originalFileSize+parts)-1)/parts;
printf("Each part is %.9f Kilobytes large.\n",(double)partSize/1024 );
partNumber=1;
printf("Part number: %d\n", partNumber);
if ((openDescriptor = open(fileName, O_WRONLY )) == -1)
{
printf("Error creating %s\n", fileName);
exit(EXIT_FAILURE);
}
ssize_t count, total;
total = 0;
char *bufff = BUFFER;
while (partSize) {
count = read(openDescriptorOriginal, bufff, partSize);
if (count < 0) {
// handle error
break;
}
if (count == 0)
break;
bufff += count;
total += count;
partSize -= count;
}
write (openDescriptor, BUFFER, total);
printf("\n");
return 0;
}
Some initial problems:
add the CREAT flag to your open() in case the file isn't there.
partSize should not be adjusted
Take out the line where you adjust partSize and it should work.
int bytesReceived;
.... open files ....
while ((bytesReceived = read(openDescriptorOriginal, BUFFER, sizeof(BUFFER)) > 0) {
if (bytesReceived != write(openDescriptor, BUFFER, bytesReceived) {
printError(...);
}
}
I would like to understand how message queues in Unix work. I wrote a simple code which sends a short message to queue and then I can read that message. But my code shows :
And I dont know why - and I cant see a message I send to queue. Heres my code:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
struct mymsgbuf {
long mtype;
char mtext[1024];
}msg;
int send_message(int qid, struct mymsgbuf *buffer )
{
int result = -1, length = 0;
length = sizeof(struct mymsgbuf) - sizeof(long);
if((result = msgsnd(qid, buffer, length, 0)) == -1)
return -1;
return result;
}
int read_message(int qid, long type, struct mymsgbuf *buffer)
{
int result, length;
length = sizeof(struct mymsgbuf) - sizeof(long);
if((result = msgrcv(qid, buffer, length, type, 0)) == -1)
return -1;
printf("Type: %ld Text: %s\n", buffer->mtype, buffer->mtext);
return result;
}
int main(int argc, char **argv)
{
int buffsize = 1024;
int qid = msgget(ftok(".", 0), IPC_CREAT | O_EXCL);
if (qid == -1)
{
perror("msgget");
exit(1);
}
msg.mtype = 1;
strcpy(msg.mtext, "my simple msg");
if((send_message(qid, &msg)) == -1)
{
perror("msgsnd");
exit(1);
}
if((read_message(qid, 1, &msg) == -1))
{
perror("msgrcv");
exit(1);
}
return 0;
}
When I changed a line with msgget for this line:
int qid = msgget(ftok(".", 0), IPC_CREAT | O_EXCL | 0600);
it shows:
From the documentation for msgget:
The low-order 9 bits of msg_perm.mode shall be set equal to the low-order 9 bits of msgflg.
You need to add some permissions to your queue, at least read and write. Do something like:
int qid = msgget(ftok(".", 0), IPC_CREAT | O_EXCL | 0600);
Here I have to send and receive dynamic data using a SysV message queue.
so in structure filed i have dynamic memory allocation char * because its size may be varies.
so how can i receive this type of message at receiver side.
Please let me know how can i send dynamic length of data with message queue.
I am getting problem in this i posted my code below.
send.c
/*filename : send.c
*To compile : gcc send.c -o send
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msgbuf {
long mtype;
char *mtext;
};
int main(void)
{
struct my_msgbuf buf;
int msqid;
key_t key;
static int count = 0;
char temp[5];
int run = 1;
if ((key = ftok("send.c", 'B')) == -1) {
perror("ftok");
exit(1);
}
printf("send.c Key is = %d\n",key);
if ((msqid = msgget(key, 0644 | IPC_CREAT)) == -1) {
perror("msgget");
exit(1);
}
printf("Enter lines of text, ^D to quit:\n");
buf.mtype = 1; /* we don't really care in this case */
int ret = -1;
while(run) {
count++;
buf.mtext = malloc(50);
strcpy(buf.mtext,"Hi hello test message here");
snprintf(temp, sizeof (temp), "%d",count);
strcat(buf.mtext,temp);
int len = strlen(buf.mtext);
/* ditch newline at end, if it exists */
if (buf.mtext[len-1] == '\n') buf.mtext[len-1] = '\0';
if (msgsnd(msqid, &buf, len+1, IPC_NOWAIT) == -1) /* +1 for '\0' */
perror("msgsnd");
if(count == 100)
run = 0;
usleep(1000000);
}
if (msgctl(msqid, IPC_RMID, NULL) == -1) {
perror("msgctl");
exit(1);
}
return 0;
}
receive.c
/* filename : receive.c
* To compile : gcc receive.c -o receive
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msgbuf {
long mtype;
char *mtext;
};
int main(void)
{
struct my_msgbuf buf;
int msqid;
key_t key;
if ((key = ftok("send.c", 'B')) == -1) { /* same key as send.c */
perror("ftok");
exit(1);
}
if ((msqid = msgget(key, 0644)) == -1) { /* connect to the queue */
perror("msgget");
exit(1);
}
printf("test: ready to receive messages, captain.\n");
for(;;) { /* receive never quits! */
buf.mtext = malloc(50);
if (msgrcv(msqid, &buf, 50, 0, 0) == -1) {
perror("msgrcv");
exit(1);
}
printf("test: \"%s\"\n", buf.mtext);
}
return 0;
}
A couple of ways to solve your problem are:
Make the messages fixed length.
Send a fixed length "header" that includes the message length.
Send a terminator, since you seem to send strings include the terminating '\0'.
Edit: How to use msgsnd and msgrcv:
Your usage of the structure and msgsnd is wrong, as the function expects the whole message to be one continuous memory area. Examples such as this use a structure with normal fields in it, or like this (at the bottom) which uses a fixed length string array.
You can send dynamic data having the structure size being dynamic as well. The trick here is to use a small fixed-size structure, and allocate more data than is needed.
Lets rewrite parts of your example sender code:
struct my_msgbuf {
long mtype; /* Message type, must be > 0 */
char mtext[1]; /* Some compilers allow `char mtext[0]` */
};
/* ... */
int count = 0;
while (count < 100) {
count++;
/* Put string in a temporary place */
char tmp[64];
snprintf(tmp, sizeof(tmp), "Hi hello test message here %d", count);
/* +1 for the terminating '\0' */
size_t msgsz = strlen(tmp) + 1;
/* Allocate structure, and memory for the string, in one go */
struct my_msgbuf *buf = malloc(sizeof(struct my_msgbuf) + msgsz);
/* Set up the message structure */
buf->mtype = 1;
memcpy(buf->mtext, tmp, msgsz);
/* And send the message */
msgsnd(msgid, buf, msgsz, IPC_NOWAIT);
/* Remember to free the allocated memory */
free(buf);
}
The above code handles sending of dynamic strings, as long as the are less than 63 characters (the size of the temporary string minus one).
Unfortunately msgrcv doesn't really support receiving of dynamically sized data. This can be helped by not using the MSG_NOERROR flag, and check for error E2BIG and then using realloc to get a bigger message buffer.
Something like this for receiving:
/* Should start with larger allocation, using small just for example */
size_t msgsz = 8;
struct my_msgbuf *buf = NULL;
for (;;) {
/* Allocate if `buf` is NULL, otherwise reallocate */
buf = realloc(buf, msgsz);
/* Receive message */
ssize_t rsz = msgrcv(msgid, buf, msgsz, 1, 0);
if (rsz == -1) {
if (errno == E2BIG)
msgsz += 8; /* Increase size to reallocate and try again */
else {
perror("msgrcv");
break;
}
} else {
/* Can use `buf->mtext` as a string, as it already is zero-terminated */
printf("Received message of length %d bytes: \"%s\""\n", rsz, buf->mtext);
break;
}
}
if (buf != NULL)
free(buf);
The above code for receiving only receives one single message. If you want it to match the sender which sends lots of messages, then put the receiving code in a function, and call it in a loop.
DISCLAIMER: This code is written directly in the browser, only reading the manual pages. I have not tested it.