|
Child Thread fails to update Shared Memory Correctly
I was wondering if someone where could help with this. I am working with Unix Shared Memory and BSD Sockets for the first time. I wrote a small little program that basically is supposed to take in multiple client connections, add their IP address to a class called "ChatClients", and then add this to a vector. The vector is created in the shared memory segment. The parent program can create this just fine, and the child can read the shared memory segment without any problems, however, when the forked child process attempts to add to the vector, or if the push back succeeds, read that element, the program hangs. Below is the code.
/////////////////////////////////////////////////////////////////////////////////
/* A very simple chat server. Accepts connections, uses shared memory since I have never worked with
* Shared memory before
*/
//needed for out networking functionality
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//needed for the Shared Memory Functionality
#include <sys/ipc.h>
#include <sys/shm.h>
//Needed for our dynamic array type structure
#include <vector>
//console based IO library
#include <iostream>
//string library
#include <string>
//Our iterator class for the clients vector
#include <iterator>
//Classes for the clients connection
#include "../Classes/chatclient.h"
using namespace std;
//These are our function declarations
void error(const string &);
int main(int argc, char *argv[])
{
//Variables for our network sockets
int sockfd, newsockfd, portno, clilen, pid;
struct sockaddr_in serv_addr, cli_addr;
//Client information
//Note: removed incoming_chat as a pointer and changed to regular variable, did not need to dynamically
//allocate
ChatClient incoming_chat; //pointer for incoming chat clients
vector<ChatClient> *clients_vector; //Vector for storing the incoming clients
//Variables for our Shared Memory Segment
key_t key;
int shmid;
//The size of our shared memory segment, set to the size of the clients vector type * 1000
int SHM_SIZE = sizeof(*clients_vector) * 1000;
//Be verbose, let the console know how large the shared memory segment is set to
cout << "Size of Shared Memory Segment: " << SHM_SIZE << endl;
//We do not want any geeky stuff happening with the child processes later on, so set this up so that
//the parent does not need to wait for the child to terminate
signal(SIGCLD, SIG_IGN);
//If there are not the appropriate command line options, exit the program
if (argc < 2) {
cerr << "ERROR, no port provided on the command line" << endl;
exit(1);
}
//Create our shared memory key
if ((key = ftok("server.cpp", 'J')) == -1)
error("Failed to FTOK");
//Connect to the shared memory segment and get the shared memory ID
if ((shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT)) == -1)
error("shmget attempt failed");
// point the clients vector to the segment
clients_vector = (vector<ChatClient> *)shmat(shmid, NULL, 0);
if (clients_vector == (vector<ChatClient> *)(-1))
error("shmat failure");
//Lets try and create a socket
cout << "Initializing the servers socket" << endl;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
//If the socket file descriptor is less than zero, an error occured, so exit gracefully
if (sockfd < 0)
error("ERROR opening socket");
//clear out the server address
cout << "Zeroing out the server address structure" << endl;
bzero((char *) &serv_addr, sizeof(serv_addr));
//Take the port number and convert it into an integer
cout << "Converting port number passed from command line to an integer" << endl;
portno = atoi(argv[1]);
//Set up our server information
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
//try and bind the socket file descriptor to the server
cout << "Binding the socket" << endl;
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
//Set up the socket to listen
cout << "Binding succeeded, listening for incoming connections" << endl;
listen(sockfd, 5);
//Get the size of the client address struture for incoming connection.
clilen = sizeof(cli_addr);
//Lets see if this crashes our vector
cout << endl << "Being memory test of chat client vector shared memory area" << endl;
for (int x = 0; x < 100; x++)
{
//cout << "Setting IP Address" << endl;
incoming_chat.set_ip_address("192.168.100.105");
//cout << "Adding to vector" << endl;
clients_vector->push_back(incoming_chat);
cout << "Vector count: " << clients_vector->size() << endl;
cout << "Freeing memory" << endl;
}
cout << "Vector test succeeded, current vector size is: " << clients_vector->size() << endl;
//Repeat indefinitly
while (1) {
//For incoming connections, set the newsockfd to accept the incoming socket
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
cout << "Recieved Connections" << endl;
if (newsockfd < 0)
error("ERROR on accept");
//Since we have accpted the socket, fork a new process and exit
cout << "Forking Process" << endl;
pid = fork();
if (pid < 0)
error("ERROR on fork");
if (pid == 0) {
//If this is the child socket, close out the main socket file descriptor to avoid problems
//and continue on with the newsockfd.
close(sockfd);
cout << "Size of vector from the start: " << clients_vector->size() << endl;
//Get the IP Address of the incoming chat client
cout << "Setting the chat clients IP address" << endl;
incoming_chat.set_ip_address(inet_ntoa(cli_addr.sin_addr));
cout << "Address of clients vector: " << clients_vector << endl;
//Add our new chat request to the clients vector
cout << "Adding chat client to the clients vector" << endl;
clients_vector->push_back(incoming_chat);
//Just a simple section to figure out what the hell is wrong with this stupid vector
vector<ChatClient>::iterator i;
int y = 0;
cout << "Preparing to go through each element in the vector to output" << endl;
for (i = clients_vector->begin(); i <= clients_vector->end(); i++)
cout << "Connection " << y++ << " from: " << i->get_ip_address() << endl;
//output the vector size
cout << clients_vector->size() << endl;
//generic do something section, just read in text message and echo back to the screen
char buffer[255];
bzero(buffer, 255);
if ((read(newsockfd,buffer,255)) < 0)
error("ERROR reading from socket");
cout << "Here is the message: " << buffer << endl;
if ((write(newsockfd,"I got your message\n",18)) < 0)
error("ERROR writing to socket");
//Removed, the exit will detatch us from the segment automatically
/* detach from the segment: */
//if (shmdt((char *)clients_vector) == -1)
// error("shmdt");
//Exit child process
exit(0);
}
else
//Otherwise this is still the parent, and we do not want to interfere with the childs communication with its
//client, so close the newsocket file descriptor
close(newsockfd);
}
return 0; /* we never get here */
}
//A generic function to print out error messages and panic out of the program
void error(const string &error)
{
cerr << "Error has occured: " << error << endl;
exit(1);
}
Last edited by admin : 12-Jul-2005 at 15:20.
Reason: please insert your example C codes between [c] and [/c] bbcode tags
|