I have created a msq to let two processes communicate to one another. The problem is that I'm having some issues since after a couple of time that I run my code some of the old messages of the previous executions show up. This bothers me because I need to perform controls on the current data and cant do it because of this. I tried irpcm -q msqid but it does not do anything except shutting down my program the next time I run it. I even tried hardcoding some keys thinking that it would help but nothing. Also tried to msgctl(msqid, IPC_RMID, 0) after I finished using the queue but nothing. Hope you can help me out and thanks in advance.
Here is my code:
sender.c
#define MAXSIZE 1024
struct msgbuf
{
long mtype;
char mtext[MAXSIZE];
};
void die(char *s)
{
perror(s);
exit(1);
}
int msqid1;
int msgflg = IPC_CREAT | 0666;
key_t keymq1;
struct msgbuf sbuf;
size_t buflen;
keymq1 = 668;
sbuf.mtype = 1;
if ((msqid1 = msgget(keymq1, msgflg )) < 0)
die("msgget");
sbuf.mtype = 1;
strcpy(sbuf.mtext,"my message");
buflen = strlen(sbuf.mtext) + 1 ;
if (msgsnd(msqid1, &sbuf, buflen, IPC_NOWAIT) < 0)
{
printf ("%d, %ld, %s, %zu\n", msqid1, sbuf.mtype, sbuf.mtext, buflen);
die("msgsnd");
}
else {
printf("Message sent\n");
}
receiver.c
#define MAXSIZE 1024
struct msgbuf
{
long mtype;
char mtext[MAXSIZE];
};
void die(char *s)
{
perror(s);
exit(1);
}
int msqid;
key_t keymq1;
struct msgbuf rcvbuffer;
keymq1 = 668;
if ((msqid = msgget(keymq1, 0666)) < 0)
die("msgget()");
if (msgrcv(msqid, &rcvbuffer, MAXSIZE, 1, 0) < 0)
die("msgrcv");
printf("Message received: %s\n", rcvbuffer.mtext);
To delete message queue with message queue Id use
ipcrm -q id
or delete the message queue using key value as
ipcrm -Q key_num
From man page "In order to delete such objects, you must be superuser, or the cre‐
ator or owner of the object."
Finally you can delete the message queue using IPC_RMID flag in msgctl() call as
main()
{
int total_mq,i,msqid;
struct msqid_ds ds; //dataStructure holding complete info for indexed message que
struct msginfo msginfo; //general buff copying data from MSG_INFO, has info of how many message que present right now
/* Obtain size of kernel 'entries' array */
total_mq = msgctl(0, MSG_INFO, (struct msqid_ds *) &msginfo); //copy kernel MSGQ_INFO to local buff
//returns count of active message Q
if (total_mq < 0)
{
perror("msgctl");
return 0;
}
printf("no of active message queue(KEY) : %d\n", total_mq+1);
/* Retrieve meaasge Queue id's */
for (i = 0; i <= total_mq; i++)
{
msqid = msgctl(i, MSG_STAT, &ds); //from each index using MSG_STAT -> ds, return msgqid
if (msqid <0 )
{
perror("msgctl");
return 0;
}
/* using msgqid remove the message queue */
if ( msgctl(msqid,IPC_RMID,0) < 0 )
{
perror("msgctl");
return 0;
}
}
printf("all message queues removed\n");
return 0;
}
before running above code, create some message queues and then delete those.
Related
I have a client program and a server program. There could be multiple servers and multiple
clients that can connect to multiple servers of there choice
The client program lists a menu
connect 4000 // connects to server on port 4000
bid 1000 4000 // send a bid value of 1000 to the server at port 4000
Now a server may recieve bids from several clients connected to it and keeps track of the highest
bid till now. Whenever a new bid is placed the server sends a broadcast to each client connected
to it one by one like - write(users[i].sock_fd, msg, size).
How do I listen to this message on the client side ?
There are two things here
The client needs to listen to the message sent by server.
The client is also reading the text or menu items (connect and bid) from command line from the user.
I have coded the part 2) But confused how to code 1) into client and simultaneously make the 2) also working
Client code :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define BUF_SIZE 128
#define MAX_AUCTIONS 5
#ifndef VERBOSE
#define VERBOSE 0
#endif
#define ADD 0
#define SHOW 1
#define BID 2
#define QUIT 3
/* Auction struct - this is different than the struct in the server program
*/
typedef struct auction_data
{
int sock_fd;
char item[BUF_SIZE];
int current_bid;
} auction_data;
auction_data *auction_data_ptr;
/* Displays the command options available for the user.
* The user will type these commands on stdin.
*/
void print_menu()
{
printf("The following operations are available:\n");
printf(" show\n");
printf(" add <server address> <port number>\n");
printf(" bid <item index> <bid value>\n");
printf(" quit\n");
}
/* Prompt the user for the next command
*/
void print_prompt()
{
printf("Enter new command: ");
fflush(stdout);
}
/* Unpack buf which contains the input entered by the user.
* Return the command that is found as the first word in the line, or -1
* for an invalid command.
* If the command has arguments (add and bid), then copy these values to
* arg1 and arg2.
*/
int parse_command(char *buf, int size, char *arg1, char *arg2)
{
int result = -1;
char *ptr = NULL;
if (strncmp(buf, "show", strlen("show")) == 0)
{
return SHOW;
}
else if (strncmp(buf, "quit", strlen("quit")) == 0)
{
return QUIT;
}
else if (strncmp(buf, "add", strlen("add")) == 0)
{
result = ADD;
}
else if (strncmp(buf, "bid", strlen("bid")) == 0)
{
result = BID;
}
ptr = strtok(buf, " "); // first word in buf
ptr = strtok(NULL, " "); // second word in buf
if (ptr != NULL)
{
strncpy(arg1, ptr, BUF_SIZE);
}
else
{
return -1;
}
ptr = strtok(NULL, " "); // third word in buf
if (ptr != NULL)
{
strncpy(arg2, ptr, BUF_SIZE);
return result;
}
else
{
return -1;
}
return -1;
}
/* Connect to a server given a hostname and port number.
* Return the socket for this server
*/
int add_server(char *hostname, int port)
{
// Create the socket FD.
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
{
perror("client: socket");
exit(1);
}
// Set the IP and port of the server to connect to.
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
struct addrinfo *ai;
/* this call declares memory and populates ailist */
if (getaddrinfo(hostname, NULL, NULL, &ai) != 0)
{
close(sock_fd);
return -1;
}
/* we only make use of the first element in the list */
server.sin_addr = ((struct sockaddr_in *)ai->ai_addr)->sin_addr;
// free the memory that was allocated by getaddrinfo for this list
freeaddrinfo(ai);
// Connect to the server.
if (connect(sock_fd, (struct sockaddr *)&server, sizeof(server)) == -1)
{
perror("client: connect");
close(sock_fd);
return -1;
}
if (VERBOSE)
{
fprintf(stderr, "\nDebug: New server connected on socket %d. Awaiting item\n", sock_fd);
}
return sock_fd;
}
/* ========================= Add helper functions below ========================
* Please add helper functions below to make it easier for the TAs to find the
* work that you have done. Helper functions that you need to complete are also
* given below.
*/
/* Print to standard output information about the auction
*/
void print_auctions(struct auction_data *a, int size)
{
printf("Current Auctions:\n");
for (int i = 0; i < size; i++)
{
struct auction_data auction_data = a[i];
printf("(%d) %s bid = %d\n", i, auction_data.item, auction_data.current_bid);
}
/* TODO Print the auction data for each currently connected
* server. Use the follosing format string:
* "(%d) %s bid = %d\n", index, item, current bid
* The array may have some elements where the auction has closed and
* should not be printed.
*/
}
/* Process the input that was sent from the auction server at a[index].
* If it is the first message from the server, then copy the item name
* to the item field. (Note that an item cannot have a space character in it.)
*/
void update_auction(char *buf, int size, struct auction_data *a, int index)
{
// TODO: Complete this function
// fprintf(stderr, "ERROR malformed bid: %s", buf);
// printf("\nNew bid for %s [%d] is %d (%d seconds left)\n", );
}
int main(void)
{
char name[BUF_SIZE];
int size = 0;
// Declare and initialize necessary variables
// TODO
// Get the user to provide a name.
printf("Please enter a username: ");
fflush(stdout);
int num_read = read(STDIN_FILENO, name, BUF_SIZE);
printf("%s-name\n", name);
if (num_read <= 0)
{
fprintf(stderr, "ERROR: read from stdin failed\n");
exit(1);
}
print_menu();
// TODO
char server_reply[2000];
while (1)
{
print_prompt();
char *command;
scanf("%m[^\n]s", &command);
getchar();
char arg1[100];
char arg2[100];
int commandNumber = parse_command(command, 1000, arg1, arg2);
char dest[100] = "";
strcpy(dest, name);
dest[strlen(dest) - 1] = '\0';
if (commandNumber == ADD)
{
printf("%s-name4\n", dest);
int port = atoi(arg2);
int sock_fd = add_server(arg1, port);
printf("%s-server\n", server_reply);
write(sock_fd, dest, strlen(dest));
auction_data_ptr = (auction_data *)realloc(auction_data_ptr, (size + 1) * sizeof(auction_data_ptr));
auction_data_ptr[size].sock_fd = sock_fd;
size++;
}
else if (commandNumber == SHOW)
{
print_auctions(auction_data_ptr, size);
}
else if (commandNumber == BID)
{
int itemIndex = atoi(arg1);
int bidValue = atoi(arg2);
printf("%d-test\n", auction_data_ptr[itemIndex].sock_fd);
send(auction_data_ptr[itemIndex].sock_fd, arg2, strlen(arg2), 0);
}
else if (commandNumber == QUIT)
{
}
// TODO
}
return 0; // Shoud never get here
}
Server Code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifndef PORT
#define PORT 30000
#endif
#define MAX_BACKLOG 5
#define MAX_CONNECTIONS 20
#define BUF_SIZE 128
#define MAX_NAME 56
int verbose = 0;
struct user
{
int sock_fd;
char name[MAX_NAME];
int bid;
};
typedef struct
{
char *item;
int highest_bid; // value of the highest bid so far
int client; // index into the users array of the top bidder
} Auction;
/*
* Accept a connection. Note that a new file descriptor is created for
* communication with the client. The initial socket descriptor is used
* to accept connections, but the new socket is used to communicate.
* Return the new client's file descriptor or -1 on error.
*/
int accept_connection(int fd, struct user *users)
{
int user_index = 0;
while (user_index < MAX_CONNECTIONS && users[user_index].sock_fd != -1)
{
user_index++;
}
if (user_index == MAX_CONNECTIONS)
{
fprintf(stderr, "server: max concurrent connections\n");
return -1;
}
int client_fd = accept(fd, NULL, NULL);
if (client_fd < 0)
{
perror("server: accept");
close(fd);
exit(1);
}
users[user_index].sock_fd = client_fd;
users[user_index].name[0] = '\0';
return client_fd;
}
/* Remove \r\n from str if the characters are at the end of the string.
* Defensively assuming that \r could be the last or second last character.
*/
void strip_newline(char *str)
{
if (str[strlen(str) - 1] == '\n' || str[strlen(str) - 1] == '\r')
{
if (str[strlen(str) - 2] == '\r')
{
str[strlen(str) - 2] = '\0';
}
else
{
str[strlen(str) - 1] = '\0';
}
}
}
/*
* Read a name from a client and store in users.
* Return the fd if it has been closed or 0 otherwise.
*/
int read_name(int client_index, struct user *users)
{
int fd = users[client_index].sock_fd;
/* Note: This is not the best way to do this. We are counting
* on the client not to send more than BUF_SIZE bytes for the
* name.
*/
int num_read = read(fd, users[client_index].name, MAX_NAME);
if (num_read == 0)
{
users[client_index].sock_fd = -1;
return fd;
}
users[client_index].name[num_read] = '\0';
strip_newline(users[client_index].name);
if (verbose)
{
fprintf(stderr, "[%d] Name: %s\n", fd, users[client_index].name);
}
/*
if (num_read == 0 || write(fd, buf, strlen(buf)) != strlen(buf)) {
users[client_index].sock_fd = -1;
return fd;
}
*/
return 0;
}
/* Read a bid from a client and store it in bid.
* If the client does not send a number, bid will be set to -1
* Return fd if the socket is closed, or 0 otherwise.
*/
int read_bid(int client_index, struct user *users, int *bid)
{
printf("inside bid\n");
int fd = users[client_index].sock_fd;
char buf[BUF_SIZE];
char *endptr;
int num_read = read(fd, buf, BUF_SIZE);
if (num_read == 0)
{
return fd;
}
buf[num_read] = '\0';
if (verbose)
{
fprintf(stderr, "[%d] bid: %s", fd, buf);
}
// Check if the client sent a valid number
// (We are not checking for a good bid here.)
errno = 0;
*bid = strtol(buf, &endptr, 10);
if (errno != 0 || endptr == buf)
{
*bid = -1;
}
return 0;
}
void broadcast(struct user *users, char *msg, int size)
{
for (int i = 0; i < MAX_CONNECTIONS; i++)
{
if (users[i].sock_fd != -1)
{
if (write(users[i].sock_fd, msg, size) == -1)
{
// Design flaw: can't remove this socket from select set
close(users[i].sock_fd);
users[i].sock_fd = -1;
}
}
}
}
int prep_bid(char *buf, Auction *a, struct timeval *t)
{
// send item, current bid, time left in seconds
printf("robin2-%s-%d\n", a->item, a->highest_bid);
printf("robin-%ld\n", t->tv_sec);
sprintf(buf, "%s %d %ld", a->item, a->highest_bid, t->tv_sec);
printf("robin-bid2\n");
return 0;
}
/* Update auction if new_bid is higher than current bid.
* Write to the client who made the bid if it is lower
* Broadcast to all clients if the bid is higher
*/
int update_bids(int client_index, struct user *users,
int new_bid, Auction *auction, struct timeval *t)
{
char buf[BUF_SIZE];
if (new_bid > auction->highest_bid)
{
auction->highest_bid = new_bid;
auction->client = client_index;
prep_bid(buf, auction, t);
if (verbose)
{
fprintf(stderr, "[%d] Sending to %d:\n %s\n",
getpid(), users[client_index].sock_fd, buf);
}
broadcast(users, buf, strlen(buf) + 1);
}
else
{
fprintf(stderr, "Client %d sent bid that was too low. Ignored\n",
client_index);
}
return 0;
}
int main(int argc, char **argv)
{
argc = 7;
argv[1] = "-v";
argv[2] = "-t";
argv[3] = "5";
argv[4] = "-p";
argv[5] = "4000";
argv[6] = "robin";
Auction auction;
int opt;
int port = PORT;
struct timeval timeout;
struct timeval *time_ptr = NULL;
int minutes = 0;
while ((opt = getopt(argc, argv, "vt:p:")) != -1)
{
switch (opt)
{
case 'v':
verbose = 1;
break;
case 't':
minutes = atoi(optarg);
timeout.tv_sec = minutes * 60;
timeout.tv_usec = 0;
time_ptr = &timeout;
break;
case 'p':
port = atoi(optarg);
break;
default:
fprintf(stderr, "Usage: auction_server [-v] [-t timeout] [-p port] item\n");
exit(1);
}
}
if (optind >= argc)
{
fprintf(stderr, "Expected argument after options\n");
exit(1);
}
auction.item = argv[optind];
auction.client = -1;
auction.highest_bid = -1;
struct user users[MAX_CONNECTIONS];
for (int index = 0; index < MAX_CONNECTIONS; index++)
{
users[index].sock_fd = -1;
users[index].name[0] = '\0';
}
// Create the socket FD.
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
{
perror("server: socket");
exit(1);
}
// Set information about the port (and IP) we want to be connected to.
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = INADDR_ANY;
// This sets an option on the socket so that its port can be reused right
// away. Since you are likely to run, stop, edit, compile and rerun your
// server fairly quickly, this will mean you can reuse the same port.
int on = 1;
int status = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
(const char *)&on, sizeof(on));
if (status == -1)
{
perror("setsockopt -- REUSEADDR");
}
// This should always be zero. On some systems, it won't error if you
// forget, but on others, you'll get mysterious errors. So zero it.
memset(&server.sin_zero, 0, 8);
// Bind the selected port to the socket.
if (bind(sock_fd, (struct sockaddr *)&server, sizeof(server)) < 0)
{
perror("server: bind");
close(sock_fd);
exit(1);
}
// Announce willingness to accept connections on this socket.
if (listen(sock_fd, MAX_BACKLOG) < 0)
{
perror("server: listen");
close(sock_fd);
exit(1);
}
if (verbose)
{
fprintf(stderr, "[%d] Ready to accept connections on %d\n",
getpid(), port);
}
// The client accept - message accept loop. First, we prepare to listen
// to multiple file descriptors by initializing a set of file descriptors.
int max_fd = sock_fd;
fd_set all_fds;
FD_ZERO(&all_fds);
FD_SET(sock_fd, &all_fds);
while (1)
{
// select updates the fd_set it receives, so we always use a copy
// and retain the original.
fd_set listen_fds = all_fds;
int nready;
if ((nready = select(max_fd + 1, &listen_fds, NULL, NULL, time_ptr)) == -1)
{
perror("server: select");
exit(1);
}
if (nready == 0)
{
char buf[BUF_SIZE];
sprintf(buf, "Auction closed: %s wins with a bid of %d\r\n",
users[auction.client].name, auction.highest_bid);
printf("%s", buf);
broadcast(users, buf, BUF_SIZE);
exit(0);
}
// Is it the original socket? Create a new connection ...
if (FD_ISSET(sock_fd, &listen_fds))
{
int client_fd = accept_connection(sock_fd, users);
if (client_fd != -1)
{
if (client_fd > max_fd)
{
max_fd = client_fd;
}
FD_SET(client_fd, &all_fds);
if (verbose)
{
fprintf(stderr, "[%d] Accepted connection on %d\n",
getpid(), client_fd);
}
}
}
// Next, check the clients.
for (int index = 0; index < MAX_CONNECTIONS; index++)
{
if (users[index].sock_fd > -1 && FD_ISSET(users[index].sock_fd, &listen_fds))
{
int client_closed = 0;
int new_bid = 0;
if (users[index].name[0] == '\0')
{
client_closed = read_name(index, users);
if (client_closed == 0)
{
char buf[BUF_SIZE];
prep_bid(buf, &auction, time_ptr);
if (verbose)
{
fprintf(stderr, "[%d] Sending to %d:\n %s\n",
getpid(), users[index].sock_fd, buf);
}
if (write(users[index].sock_fd, buf, strlen(buf) + 1) == -1)
{
fprintf(stderr, "Write to %d failed\n", sock_fd);
close(sock_fd);
}
}
}
else
{ // read a bid
client_closed = read_bid(index, users, &new_bid);
if (client_closed == 0)
{
update_bids(index, users, new_bid, &auction, time_ptr);
}
}
if (client_closed > 0)
{
FD_CLR(client_closed, &all_fds);
printf("Client %d disconnected\n", client_closed);
}
}
}
}
// Should never get here.
return 1;
}
Caveat: Because you've only posted partial code for server and client, this will be some suggestions.
Your client can attach/connect to multiple bid servers simultaneously. As such, it must be able to keep track of the multiple connections in a manner similar to a server.
Your main [stated] issue is that you're blocking the client on a user prompt (e.g. from stdin via scanf et. al.). Presently, this means that the client is "stuck" at user input prompt and can not field messages from the servers it is connected to. More on how to fix this below.
So, you'll have a bunch of code from the server that needs to be in the client with some minor differences. You may wish to generalize some of the server code a bit, so it can work both in server and client (e.g. you may want to move it to common.c).
You already have code in the server to handle multiple connections. The server needs a select mask that is the OR of the listen fd and all active client fds.
Likewise, your client needs a select mask that is the OR of the fd for user input (e.g. 0) and all active server connections.
Doing select on fd 0 and using stdio.h streams won't work too well. So, replace access to stdin with (e.g.) read(0,line_buffer,sizeof(line_buffer)). You do this if fd 0 is set in the select mask. The role is very similar to what your server does for the accept on sock_fd.
You'll need to allow for partial reads and append to the buffer until you see a newline. So, you'll have to do the work that fgets would normally do in assembling a whole line. Then, you can call parse_command.
Because read doesn't understand newline demarcations, the user could enter more than one line before you can do a read.
So, for user input of:
connect 4000\n
bid 100 4000\n
connect 5000\n
You may get partial reads of:
conn
ect
4000\nbid 100 4000
\nconnect
5000\n
You may also need to use the FIONREAD ioctl on the fd 0 to prevent blocking. And, you may need to set the kernel TTY layer into raw mode via termios calls.
The client now becomes very similar to your server code. It will handle [asynchronously] actions by any connected servers and user input.
A tip: Under the DRY principle ["don't repeat yourself"] ...
You already have a struct user in the server. The client will need something similar/identical, such as struct server. When generalizing the code, rather than having two distinct structs that do essentially the same thing, consider renaming the existing struct to (e.g.) struct connection
*I'm using message queues for sending and receiving messages but some parameters in the the structure msqid_ds no giving proper values why it happens?
*Time of last message send=1525240214- why this is showing junk values?
struct mesg_q
{
char msg_txt[100];
long msg_typ;
};
int main()
{
int msgid;
key_t key;
char buffer[100];
struct mesg_q msgq;
struc answerst msqid_ds info;
// key = ftok("/home/yash72/krishna/thread_test/msgq.text", 65);
msgid=msgget((key_t)1234, 0666 | IPC_CREAT);
if(msgid== -1)
{
printf("msgget failed\n");
return -1;
}
while(1)
{
printf("Text Message\n");
fgets(msgq.msg_txt,100,stdin);
if(msgsnd(msgid,&msgq,100,0)==-1)
{
printf("Send failed\n");
return -1;
}
else
{
printf("Message send\n");
}
msgctl(msgid, IPC_STAT, &info);
printf("Time of last message send=%d\n",info.msg_stime);
printf("uid=%d\n",info.msg_perm.uid);
}
}
OUTPUT:
Text Message
qwerty
Message send
Time of last message send=1525240214 // Why this is showing junk?
uid=0
Text Message
Receiver code:
Reason for junk values from this code?
struct mesg_q
{
char msg_txt[100];
long msg_typ;
};
int main()
{
int msgid;
char buffer[100];
long int rec_buff=0;
key_t key;
struct mesg_q msgq;
struct msqid_ds info;
// key = ftok("/home/yash72/krishna/thread_test/msgq.text", 65);
msgid=msgget((key_t)1234, 0666 | IPC_CREAT);
if(msgid == -1)
{
printf("Msgget failed\n");
return -1;
}
while(1)
{
if(msgrcv(msgid,&msgq,100,rec_buff,0)==-1)
{
printf("Mesg recv failed\n");
return -1;
}
else
{
printf("Mesg Recvd\n");
}
printf("Recvd mesg=%s\n",msgq.msg_txt);
msgctl(msgid, IPC_STAT, &info);
printf("Num:of bytes on queue= %d\n", info.msg_cbytes);
printf("num:of messages on queue=%d\n", info.msg_qnum);
printf("Max bytes on queue=%d\n", info.msg_qbytes);
printf("Time of last message recvd=%d\n",info.msg_rtime);
}
}
OUTPUT;
Number of bytes on queue= 0
number of messages on queue=0
Maximum bytes on queue=16384
Time of last message received=1525240214
what is the reason foe this incorrect values from struct msqid_ds ?
First of all you should know why to use message queue IPC, I assume before using message queue, you have gone through FIFO. In FIFO what is condition for the processes to communicate each other ? that both process should be alive while communicating.
To avoid above problem of FIFO you are using message queue, as in MQ you can put data at one time and can read at anytime, for that you have to specify the mtype i.e with what mtype process_1 is sending the data and with what mtype process_2 is receiving the data.
From the manual page of msgsnd
struct msgbuf {
long mtype; /* message type, must be > 0, I'm talking baout this */
char mtext[1]; /* message data */
};
so in both the process(reader & sender) specify the mtype
msgq.msg_typ = 1; /*specify this in both process */
Secondly, Time of last message send=1525240214- why this is showing junk values ? => Its not junk data, its the time in seconds from EPOCH time, use ctime() to print in human readable format.
sender.c
#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<stdint.h>
struct mesg_q {
char msg_txt[100];
long msg_typ;
};
int main(void) {
int msgid;
struct mesg_q msgq;
struct msqid_ds info;
msgid=msgget((key_t)1234, 0666 | IPC_CREAT);
if(msgid== -1) {
printf("msgget failed\n");
return -1;
}
while(1) {
printf("Text Message\n");
fgets(msgq.msg_txt,sizeof(msgq.msg_txt),stdin);
/* with what msg_type you are sending, you didn't mention ? mention it */
msgq.msg_typ = 1; /* I am sending with msg_type 1 */
if(msgsnd(msgid,&msgq,sizeof(msgq),msgq.msg_typ)==-1) {
printf("Send failed\n");
return -1;
}
else {
printf("Message send\n");
}
msgctl(msgid, MSG_STAT, &info);
printf("Time of last message send = %jd\n",(intmax_t)info.msg_stime);/* use the correct format specifier */
/* what ever time info.msg_stime printing, its not junk, its seconds from EPOCH, use ctime() to print in readable format */
printf("uid = %d\n",info.msg_perm.uid);
}
return 0;
}
receiver.c
struct mesg_q {
char msg_txt[100];
long msg_typ;
};
int main(void ){
int msgid;
long int rec_buff=0;
struct mesg_q msgq;
struct msqid_ds info;
msgid=msgget((key_t)1234, 0666 | IPC_CREAT);
if(msgid == -1) {
printf("Msgget failed\n");
return -1;
}
while(1) {
/* with what msg_typ you are reciving, you have to mention ? u didn't */
msgq.msg_typ = 1;
if(msgrcv(msgid,&msgq,sizeof(msgq),rec_buff, msgq.msg_typ)==-1) {
printf("Mesg recv failed\n");
return -1;
}
else{
printf("Mesg Recvd\n");
}
printf("Recvd mesg=%s\n",msgq.msg_txt);
msgctl(msgid, MSG_STAT, &info);
/* enable compiler warning, and use correct format specifier */
printf("Num:of bytes on queue= %u\n", (int)info.msg_cbytes);
printf("num:of messages on queue=%d\n", (int)info.msg_qnum);
printf("Max bytes on queue=%d\n", (int)info.msg_qbytes);
printf("Time of last message recvd=%jd\n",(intmax_t)info.msg_rtime);
}
return 0;
}
I am trying to develop a simple message queue in C but I am running towards some frustrating problems. I have a number of 10 processes that are divided in two groups of five. Each of the processes of this group must speak with only one of the processes of the other group, and to do that I have assigned different keys to the message queue creation (sorry if it is not the best idea but i'm new to C and trying to adapt). My main issue though is that when I run the code the first time if tells me that 'No such file or directory exists" as a mq error. When I run it from this point on the server receives the message just fine, but it receives the 'old' messages, which are the ones that the client has sent the prior execution. I've been trying to look for what to change but haven't come up with anything. This is my code:
server.c
int keys[] = {1111, 1112, 1113, 1114, 1115};
int msqid;
key_t keymq1;
struct msgbuf rcvbuffer;
keymq1 = keys[indiceProcesso];
if ((msqid = msgget(keymq1, 0666)) < 0)
die("msgget()");
if (msgrcv(msqid, &rcvbuffer, MAXSIZE, 1, 0) < 0)
die("msgrcv");
printf("Messaggio ricevuto da A con pid %d: %s\n",getpid(), rcvbuffer.mtext);
client.c
int msqid1;
int msgflg = IPC_CREAT | 0666;
key_t keymq1;
struct msgbuf sbuf;
size_t buflen;
keymq1 = keys[indiceProcesso];
sbuf.mtype = 1;
if ((msqid1 = msgget(keymq1, msgflg )) < 0)
die("msgget");
sbuf.mtype = 1;
strcpy(sbuf.mtext,"My message");
buflen = strlen(sbuf.mtext) + 1 ;
if (msgsnd(msqid1, &sbuf, buflen, IPC_NOWAIT) < 0)
{
printf ("%d, %ld, %s, %zu\n", msqid1, sbuf.mtype, sbuf.mtext, buflen);
die("msgsnd");
}
else
printf("Message Sent\n");
Hope you can help me out and thank you for your time.
I am implementing message queue in C linux. I am sending an integer = 17 and receiving integer = 0. Please see below and let me know what's wrong with my msgsnd and msgrcv functions.
Please give attention to this: will rbuf store data in rbuf->m->msglen or in rbuf->mtype.
In sending process
msgsnd(msqid, sbuf,sizeof(int), 0);
printf("\nmsglen = %d",rbuf->m->msglen); // 17
In receiving process. Both have same msqid. I have verified it.
msgrcv(msqid, rbuf, sizeof(int), 1, 0);
printf("\nmsglen = %d",rbuf->m->msglen); // 0
//msqid=98305, some valid id
here is my struct definations defined in another file.
typedef struct message1
{
int msglen;
unsigned char *cp;
}msg1;
typedef struct msgbuf
{
long mtype;
msg1 *m;
} message_buf;
You are sending a message which contains a pointer to your message1 struct. The receiving process dereferences that pointer, but in that process it does not point to the same thing. In fact I am surprised you didn't get a segfault.
You should define msgbuf like this:
typedef struct msgbuf
{
long mtype;
msg1 m;
} message_buf;
So that the msg1 struct is contained within the msgbuf rather than pointed to by it.
Also, the size you need to specify is sizeof(message_buf), not sizeof(int).
//header files
#include"msgbuf.h" //where I have put my structures
#define AUTOMATIC 1
#define USER_DATA 2
int main()
{
int msgflg = IPC_CREAT | 0666,ch,len=0;
size_t msgsize = 0;
int msqid;
key_t key;
message_buf *sbuf;
char ans;
char *data;
key = ftok("/home/user",15);
printf("Do you want to send messages\t");
scanf("%c",&ans);
getchar();
if (((ans=='y' || ans=='Y') && (msqid = msgget(key, msgflg )) ==-1))
{ perror("msgget");
exit(1);
}
else
fprintf(stderr,"msgget: msgget succeeded: msqid = %d\n", msqid);
while(ans=='y' || ans=='Y')
{
printf("\n1. Automatic data\n2. Enter data\n3. Exit\nEnter your choice\t");
scanf("%d",&ch);
getchar();
switch(ch)
{
case AUTOMATIC: len=strlen("Did you get this?");
sbuf=malloc(len+sizeof(int));
memset(sbuf, 0, sizeof(message_buf));
sbuf->m=malloc(len+sizeof(int));
memset(sbuf->m, 0, sizeof(msg1));
sbuf->m->msglen=len;
sbuf->m->cp=malloc(sizeof(len));
strncpy(sbuf->m->cp, "Did you get this?",strlen("Did you get this?"));
sbuf->m->cp[strlen(sbuf->m->cp)]='\0';
break;
case USER_DATA: printf("\nEnter data\t");
fflush(stdout);
len = getline(&data, &msgsize, stdin);
sbuf=malloc(len+sizeof(int));
memset(sbuf, 0, sizeof(message_buf));
sbuf->m=malloc(len+sizeof(int));
memset(sbuf->m, 0, sizeof(msg1));
strcpy(sbuf->m->cp, data);
sbuf->m->cp[strlen(sbuf->m->cp)]='\0';
sbuf->m->msglen=len;
break;
case 3: msgctl(msqid, IPC_RMID, NULL);
printf("\nQueue with q id = %d is removed\n",msqid);
exit(1);
default:printf("\nTRY AGAIN\t");
scanf("%c",&ans);
getchar();
}
printf("\nmsglen = %d\nmsgcp= %s",sbuf->m->msglen,sbuf->m->cp);
/* Send a message */
sbuf->mtype=1;
if (msgsnd(msqid, sbuf,2*sizeof(int), 0) < 0)
{
printf("Msg q id= %d\nMsg type= %d\nMsg Text %s\nMsg Len= %d\n", msqid, sbuf->mtype, sbuf->m->cp,sbuf->m->msglen);
perror("msgsnd");
exit(1);
}
else
printf("\nMessage: %s\n Sent\n", sbuf->m->cp);
}
msgctl(msqid, IPC_RMID, NULL);
printf("\nQueue with q id = %d is removed\n",msqid);
return 0;
}
Now Receiving code
//header files
#include"msgbuf.h"
int main()
{
int msqid;
key_t key;
int msgflg = 0666;
message_buf *rbuf;
int msg_len_rcvd=0;
rbuf=malloc(150);
rbuf->m=malloc(100);
key = ftok("/home/user",15);
if ((msqid = msgget(key, msgflg)) ==-1)
{
perror("msgget");
exit(1);
}
printf("\n\n%d\n",msqid);
/* Receive an answer of message type 1. */
while(1)
{
if ( (msg_len_rcvd=msgrcv(msqid, rbuf, 2*sizeof(int), 1, 0)) < 0)
{
perror("msgrcv");
exit(1);
}
else
{
printf("\n Number of bytes received:: %d", msg_len_rcvd);
printf("\nmtype1 = %d",rbuf->mtype);
printf("\nmsglen= %d",rbuf->m->msglen);
}
break;
}
return 0;
}
I'm trying to implement a program similar to this example:
the program passes an integer among 4 processes and each process decrements the integer
each process have its own mailbox
Each process check its mailbox for variable "counter" and if it was found it will decrements it
Then it send the counter variable to the next process
but there is a bug in the program and I cant find it.
note that this an assignment and Im just looking for tips that helps me find the bug.
typedef struct {
int counter;
char data[256];
int id; //id of the process that previously decremented the counter
} msg;
int main(int arqc, char *argv[]){
int key=9;
int id=0;
pid_t pid;
int num=5;
int i, k;
int arr[5];
//create 5 forks
if (arqc != 2){
num=5;
}else{
int ret = sscanf(argv[1], "%d", &num);
if (ret != 1)return 0;
}
for(i=0 ; i<num ; i++){
if ((pid = fork()) == -1) {
fprintf(stderr, "can't fork, error %d\n", errno);
exit(EXIT_FAILURE);
}
if (pid == 0) {
id=i;
}
else {
break;
}
}
//process 1 to n comes here
msg m;
int boxid = msgget(id, 0600 | IPC_CREAT);
arr[id]=boxid;
int firstRun=1;
//initiate the first move
if((id==0)&&(firstRun==1)){
m.counter = INIT_COUNTER;
//send msg to next process
msgsnd(arr[id], &m, sizeof(msg), 0); //send msg to own inbox
firstRun=0;
}
while(1){
//check inbox of current process
int rec = msgrcv(arr[id], &m, sizeof(msg), 0, 0);
printf("Im %d, counter is %d, rec is %d\n",id, m.counter, rec);
int index;
if(id==num){
index=0;
}else{
index=id+1;
}
//send message to the next inbox
int sent = msgsnd(arr[index], &m, sizeof(m), 0);
printf( "Error opening file: %s\n", strerror( errno ) );
sleep(1);
}
}
Your initial msgsnd is failing with an invalid argument and everything get munged from there on.
SysV message queues require a message type field as the first field in a message so you need to do something like this.
typedef struct
{
long int mtype;
int counter;
char data[256];
int id; //id of the process that previously decremented the counter
} msg;
You also have to set the message to something and set the correct length before you send it.
//initiate the first move
if ((id == 0) && (firstRun == 1))
{
m.mtype = 100;
m.counter = INIT_COUNTER;
strncpy(m.data, "some kind of message is nice", sizeof(m.data));
m.id = id;
size_t msgsize = sizeof(msg) - sizeof(long int);
//send msg to next process
int sent = msgsnd(arr[id], &m, msgsize, 0); //send msg to own inbox
if (sent == -1)
{
perror("msgsend");
exit(1);
}
firstRun = 0;
}
You run into problems beyond this (e.g. set the correct size on the msgrcvs) but this should get you over the initial hump.
First of all, it is unreasonable to expect the SO crowd to just solve the (homework?) problem for you without any effort on your side. It is unclear what the problem is, how the program behaves currently, and what steps were made to debug it.
Rants aside, I'd recommend cutting out all the steps leaving only two participants and getting it to work in that simple configuration. Once it works, add another one, make sure it still works and so on.