I'm trying to share some memory with an other forked+execed process using shmget and shmat:
char test[]="test";
int shID;
char *shptr;
key_t shkey = 2404;
shID = shmget(shkey, sizeof(char)*(strlen(test)+1), IPC_CREAT | 0666);
if (shID >= 0) {
shptr = shmat(shID, 0, 0);
if (shptr==(char *)-1) {
perror("shmat");
} else {
memcpy(shptr, &test, strlen(test)+1);
....
//forking and execing
....
shmdt(shptr);
}
} else {
perror("shmget");
}
This works fine.
The thing is that test[] is going to be a huge char*. So I liked easy to share text[] instead of copying it.Is there any better way to handle this?
if you can read file size or exact memory which you want to read from file and location than you can use mmap to map that part of file to memory.
Related
I don't really understand how shared memory works and I am trying to write a server-client program in which the server and client talk to each other using shared memory and semaphores.
Shared memory structure:
typedef struct shared_mem{
int board[BOARD_SIZE * BOARD_SIZE];
int goal;
int client;
int direction;
sem_t sem_server;
}shared_mem;
shared_mem *msg;
Server:
int shmid;
key_t key=ftok("2048_client.c", 42);
if(key == -1) {
printf("ftok failed");
return -1;
}
shared_mem *shm;
if ((shmid = shmget(key, sizeof(msg), IPC_CREAT|0600)) < 0) {
perror("shmget");
exit(1);
}
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
msg=shm;
int direction = -1;
srand(time(NULL));
//SERVER SETS VALUES FOR SHARED MEMORY STRUCTURE
sem_wait(&msg->sem_server);
// setup the board
initialize();
// the board starts with 2 pieces
create_game_piece();
printf("pieces created");
create_game_piece();
msg->client=0;
int i;
for (i = 0; i < BOARD_SIZE * BOARD_SIZE; i++)
msg->board[i] = board[i];
sem_post(&msg->sem_server);
// game loop
while (1) {
//CLIENT READS AND CHANGES VALUES
//SERVER READS VALUES CHANGED BY CLIENT
if (!move_board(direction))
continue;
sem_wait(&msg->sem_server);
moves++;
direction=msg->direction;
if (check_win()) {
print_board(-1);
printf("congratulations! you've won in %d moves\r\n", moves);
return 0;
}
create_game_piece();
if (!has_moves_left()) {
print_board(-1);
printf("you lose! try again\r\n");
//sleep(1);
return 1;
}
sem_post(&msg->sem_server);
}
Client:
int shmid;
key_t key=ftok("2048_client.c", 42);
if(key == -1) {
printf("ftok failed");
return -1;
}
shared_mem *shm;
msg=(shared_mem *)malloc(sizeof(shared_mem));
if ((shmid = shmget(key, sizeof(msg), IPC_CREAT|0600)) < 0) {
perror("shmget");
exit(1);
}
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
atexit(on_exit2);
system("stty raw");
srand(time(NULL));
while (1) {
// CLIENT READS VALUES CHANGED BY SERVER AND CHANGES THEM
sem_wait(&msg->sem_server);
print_board(direction);
direction = keypress();
msg->direction=direction;
sem_post(&msg->sem_server);
}
Could someone please tell me how to coordinate the way the client and server access the shared memory so that it works according to the comments in the code?
SHM_UNLOCK does not do what you think. It tries to lock pages in memory not prevent access. You need a semaphore to control access to the shared memory. See semctl, semget, etc., and employ them in both the client and server for mutually exclusive access.
There are a lot of things wrong with your code.
You did not initialize the semaphore at all. For this operation where the
semaphore is located in shared memory, make sure to set the pshared argument to nonzero.
You cannot do two-way synchronization this way with only one semaphore
(otherwise you do a sem_post, that is immediately sem_waited by the same
process, hence that thread may continue, the other one doesn't get to run).
You malloc'ed msg in the client, and never pushed it to the shared memory,
thus the shared memory is still not initialized.
What do you think system("stty raw") is going to accomplish, other than opening a seriously big can of security issues?
Obviously it wasn't runnable code. I've fixed quite a few small things, but gave up after half an hour because there's just too much wrong with it. Things like comparing a char* to a shared_mem* is wrong. Enable -Wall and -Wextra on your compiler and fix all warnings you get. Your code is full of it and unfortunately all indicate serious issues.
From a design perspective, there are even more issues.
Apparently you are using a 1-D array 'board' that is global in the server. This is not proper for two reasons:
The board is always 2-dimensional, why not use a 2D array?
You use it as a global variable, accessible by all functions. This is "javascript"-style programming. Please make the board local to main and pass it to the various functions.
I would like to create a server-client program in which the two processes pass information between each other using shared memory
information to be passed:
typedef struct shared_mem{
int board[BOARD_SIZE * BOARD_SIZE];
int goal;
}shared_mem;
shared_mem *msg;
server:
int main(int argc, char **argv) {
int shmid;
key_t key=ftok("2048_client", 42);
if(key == -1) {
printf("ftok failed");
return -1;
}
shared_mem *shm;
msg=(shared_mem *)malloc(sizeof(shared_mem));
/*
* Create the segment
*/
if ((shmid = shmget(key, sizeof(msg), IPC_CREAT)) < 0) {
perror("shmget");
exit(1);
}
/*
* Now we attach the segment to our data space.
*/
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
msg=shm;
(*msg).goal=64;
}
client:
int main(int argc, char **argv) {
int shmid;
key_t key=ftok("2048_client", 42);
if(key == -1) {
printf("ftok failed");
return -1;
}
shared_mem *shm;
msg=(shared_mem *)malloc(sizeof(shared_mem));
/*
* Create the segment.
*/
if ((shmid = shmget(key, sizeof(msg), 0)) < 0) {
perror("shmget");
exit(1);
}
/*
* Now we attach the segment to our data space.
*/
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
msg=shm;
printf("dscsadc: %d",msg->goal);
}
I am new to shared memory and i would like to understand why it doesn't work and how it is supposed to work. I am getting "shmat: Permission denied"
The problem is that you create the shared memory segment with 0000 permissions, so no-one can read or write it.
Change the shmget() call from:
if ((shmid = shmget(key, sizeof(msg), IPC_CREAT)) < 0) {
to:
if ((shmid = shmget(key, sizeof(msg), IPC_CREAT|0600)) < 0) {
Only the user running the program can access the shared memory that is created.
Note that POSIX shmget()
says:
The low-order nine bits of shm_perm.mode are set to the low-order nine bits of shmflg.
If you're not limited to C only, look at the boost library. It enables you to create shared memory segments for interprocess communication.
using boost::interprocess;
shared_memory_object shm_obj
(create_only, //only create
"shared_memory", //name
read_write //read-write mode
);
http://www.boost.org/doc/libs/1_54_0/doc/html/interprocess/sharedmemorybetweenprocesses.html
Other then that, you can always use pipes, or if you're thinking about windows - COM.
I am trying to write a file with data into my shared memory segment. However everything I have tried seems just to give the error Segmentation fault. I have been searching the internet for help for more then one day.
int main(int argc, char *argv[]).
{
int sm;
char *data;
int pid=atoi(argv[1]);
int key=atoi(argv[2]);
char (*d)[1025];
data=(char*) malloc(1025);
//put the data in the shared memory segment
FILE *file=fopen(argv[3], "r"); //r for read
if (file==0)
{printf("Could not open file");}
else
{
while(fgets(data, 1025, file)!=NULL)
{
fputs(data, file);
// puts(d);
}
fclose(file);
}
//access shared memory
//S_IWUSR gives owner the write permession
sm = shmget(key, 1024, S_IWUSR);
//create a pointer to the shared memory segment
d = shmat(sm, (void *)0, 0); //shared memory id, shmaddr, shmflg
//for (int j=0; j<100; j++)
strcpy(d[0], data);
shmdt(d); //detach the shared memory segment
//remove the shared memory segment
shmctl(sm, IPC_RMID, NULL);
}
Any help would be greatly appreciated
Thanks in advance
EDIT: added malloc
EDIT2: maybe I should rephrase my question, my problem is to get the data into my shared memory
+1 about rjayavrp answer
And I can add that data is not allocated... This is just a pointer and not a array of chars..
Moreover what are you trying to do with
char (*d)[1025];
A quick and dirty example :
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SIZE_SHARED_MEMORY 1024
int main(int argc, char *argv[])
{
int sm = -1;
char *d = NULL;
FILE *file = NULL;
key_t key = 0;
int ret = 0;
if (argc != 4)
{
return 1;
}
key = atoi(argv[2]);
//access shared memory
sm = shmget(key, SIZE_SHARED_MEMORY, IPC_CREAT | 0600);
if (sm == -1)
{
perror("shmget : Failed");
return 2;
}
//create a pointer to the shared memory segment
d = shmat(sm, (char *)0, 0);
if (d == (void *)-1)
{
perror("shmat : Failed");
return 3;
}
// Open the file
file = fopen(argv[3], "r");
if (file == NULL)
{
perror("fopen : Failed");
ret = 4;
}
else
{
if(fgets(d, SIZE_SHARED_MEMORY, file) == NULL)
{
perror("fgets : Failed");
ret = 5;
}
fclose(file);
}
shmdt(d); //detach the shared memory segment
// remove the shared memory segment ???
// Don't understand why you are doing this
shmctl(sm, IPC_RMID, NULL);
return ret;
}
File is opened in read mode only.
change it to rw+ which will open a file in read/write mode. If the file is not available, it will be created.
fputs(data, file); here file is opened in read-only mode but write is happening.
But Im not sure, why you trying to write the read data to same file. You should consider your design first. 2. char (*d)[1025]; is a pointer to an char array of size 1025. You are using it in strcpy(). 3. memory should be allocated for data either statically or dynamically.
I am trying to write a code that shares a structure type, but im getting segmentation error when tryign to write in a structure member in the shared memory, the shared memory is between a parent and child process. as im showing in the code, im just tryin to access the struct member for now, so i can use semaphore later for synch.
Thanx in advance.
typedef struct file
{
char *shmPtr;
} file_entry;
int main (void)
{
int shmid;
int n;
file_entry *entries;
if (fork() == 0) {
/*wait for a while*/
if ((shmid = shmget(20441, sizeof(file_entry), 0666)) == -1) {
printf("shmget");
exit(2);
}
entries = (file_entry*) shmat(shmid, 0, 0);
if (entries->shmPtr == (char *) -1) {
printf("problem2");
exit(2);
}
printf("\nChild Reading ....\n\n");
printf("%s\n", entries->shmPtr[0]);
printf("%s\n", entries->shmPtr[1]);
putchar('\n');
printf("\nDone\n\n");
} else {
if ((shmid = shmget(20441, sizeof(file_entry), IPC_CREAT | 0666)) == -1) {
printf("problem3");
exit(2);
}
entries = (file_entry *) shmat(shmid, 0, 0);
if (entries->shmPtr == (char *) -1) {
printf("problem4");
exit(2);
}
printf("done attachment"); /*the parent prints this statment, then segmentation fault*/
entries->shmPtr[0]='a';
entries->shmPtr[1]='b';
putchar('\n');
wait();
shmdt(&shmid);
}
exit(0);
}
shmat returns a pointer to the shared memory area. In your code, after the call to shmat, entries points to the shared region. You are then treating the first few bytes of that shared area as a pointer to char (shmPtr). The value of shmPtr is uninitialized, and it points to some random location. Then you try to write to it and get a segfault.
Edit:
As Richard suggested, you could get rid of the struct and just use a char *. However, I'm guessing the reason you are using a struct and not just a char * is that you are planning to add some extra fields to the struct in the future. If that's the case, you can use a flexible array member:
typedef struct file
{
int flag;
int blah;
char shmPtr[];
} file_entry;
and the allocation becomes
shmget(20441, sizeof(file_entry) + bufsize, IPC_CREAT | 0666)
Of course, if the buffer size is fixed, you could just hardcode it:
typedef struct file
{
int flag;
int blah;
char shmPtr[BUFSIZE];
} file_entry;
/* ... */
shmget(20441, sizeof(file_entry), IPC_CREAT | 0666)
I am new to linux environment. I just know the basics of C. I am trying to learn linux programming. For this I am trying an example on shared memory. Please someone help me with this example.
I am trying to send person details (like name, phone number & address) to another process using Shared memory. After receiving the data by the second process, I am trying to save received data into a file. This is the task I am doing.
I am able to send just the name and receive it in the second process. Can someone please help how to send the data(like name, phone number & address) to second process and in the second process it must print the data and it should save the data to a file.
Here is my code:
address.c
char *shared_memory;
int main()
{
int select;
int segment_id;
char* shared_memory;
int segment_size;
key_t shm_key;
const int shared_segment_size = 0x6500;
shm_key = ftok("/home/madan/programs/shm_tok",'C');
if(shm_key < 0) {
printf("failed to create the key %s\n",strerror(errno));
}
/* Allocate a shared memory segment. */
segment_id = shmget (shm_key, shared_segment_size,
IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
if(segment_id < 0) {
printf("error geting the segment id %s\n",strerror(errno));
}
printf("segment ID:%d\n", segment_id);
/* Attach the shared memory segment. */
shared_memory = (char*) shmat (segment_id, 0, 0);
printf ("shared memory attached at address %p\n", shared_memory);
/* I want to send these details to the shared memory. Can someone suggest me the correct way to send these details to shared memory so that second process can retrieve them*/
sprintf(shared_memory, "maddy\n");
sprintf(shared_memory, "767556686");
sprintf(shared_memory, "Ontario");
system("./address-insert");
/* Detach the shared memory segment. */
shmdt (shared_memory);
/
* Deallocate the shared memory segment.*/
shmctl (segment_id, IPC_RMID, 0);
}
addres-insert.c
int main ()
{
int segment_id;
char* shared_memory;
FILE *fp;
char *name;
int segment_size;
key_t shm_key;
shm_key = ftok("/home/madan/programs/shm_tok",'C');
const int shared_segment_size = 0x6500;
/* Allocate a shared memory segment. */
segment_id = shmget (shm_key, shared_segment_size,
S_IRUSR | S_IWUSR);
if(segment_id < 0) {
printf("error:[%s]",strerror(errno));
}
printf("segment id %d\n",segment_id);
/* Attach the shared memory segment. */
shared_memory = (char*) shmat (segment_id, 0, 0);
if(shared_memory == NULL) {
printf("failed to attach the shared memory %s",strerror(errno));
}
printf ("shared memory2 attached at address %p\n", shared_memory);
/* printing the data from shared memory send by first process*/
printf ("name=%s\n", shared_memory);
/*copying the data in shared memory so i can save them to a file*/
strcpy(name, shared_memory);
printf("%s", name);
/*here i have to save the data to a file. But i don't know how to do it, can someone help me with this please*/
/* Detach the shared memory segment. */
shmdt (shared_memory);
return 0;
}
For saving the data in a file, you can use file stream. For that you have to know about file streams.
Hope these link will help.
http://linux.die.net/man/3/fopen
http://en.wikipedia.org/wiki/C_file_input/output
Here comes the example program which I particularly typed, compiled and attached it for your reference.
#include<sys/types.h>
#include<string.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdio.h>
struct mystruct // you can make your own structure if you want to pass many data
{
int i;
float f;
char c;
int arr[3];
}myObj = {1,1.1,'C',{100,1000,10000}};
main()
{
int shmid;
char* addr1;
key_t key;
//file to key. Generates a unique key
key = ftok("/home/muthu/Desktop/anyfile.txt",'T');
shmid = shmget(key,sizeof(struct mystruct),IPC_CREAT|SHM_R|SHM_W);
printf("shmid = %d",shmid);
addr1 = shmat(shmid,0,0);
printf("\nIPC SHARED MEMORY");
//copying your structure at the shared location.
memcpy(addr1,&myObj,sizeof(myObj));
printf("\nMESSAGE STORED");
}
And for shared memory 2.....
//<All necessary header files>
//<same my struct declaration here>
main()
{
int shmid;
char* addr1;
FILE* fp;
key_t key;
struct mystruct* myObj2;
//Generate the same unique key. Must provide the same file here too.
key = ftok("/home/muthu/Desktop/anyfile.txt",'T');
shmid = shmget(key,sizeof(struct mystruct),SHM_R|SHM_W);
addr1 = shmat(shmid,0,0);
myObj2 = (struct mystruct*)malloc(sizeof(struct mystruct)*1);
if(shmid == -1)
printf("\nShared memory error");
//Retrieve the stored information, form the shared location.
memcpy(myObj2,addr1,sizeof(struct mystruct));
fp = fopen("/home/muthu/Desktop/MyFile.txt","w"); //open a file stream
if(fp == NULL)
printf("\nError on opening file stream.\n");
fprintf(fp,"\nIPC SHARED MEMORY");
fprintf(fp,"\nMESSAGE RECIEVED FORM THE SHARED MEMORY IS..\n");
fprintf(fp,"\ninteger: %d",myObj2->i);
fprintf(fp,"\nfloat: %f",myObj2->f);
fprintf(fp,"\nchar: %c",myObj2->c); //write to the file
fprintf(fp,"\narr: %d %d %d",myObj2->arr[0],myObj2->arr[1],myObj2->arr[2]);
fprintf(fp,"\nDATA RECIEVED.");
fclose(fp); //close the file stream
printf("\nMessage successfully stored!");
}
Here is a snippet that you can use
fp = fopen("filename","a+");
fwrite(name, 1, strlen(name),fp);
fclose(fp);
You can store all your three fields onto a structure and load the structure onto the Shared Memory. In this way you are assured to have all the fields under one structure.
In the process that reads the SHM you can use the File Stream utils as mentioned above by others.