I have the following INI file:
[Connection]
Protocol=HTPP
[Connection]
Protocol=HTTPS
Is there some way I can save two protocols in two different variables? I tried to write:
int a = GetPrivateProfileString(_T("Connection"), _T("Protocol"), _T(""), protocolChar, 32, path);
int ab = GetPrivateProfileString(_T("Connection"), _T("Protocol"), _T(""), protocolChar2, 32, path);
And the result is that ProtocolChar, protocolChar2, though both receive the "HTTP".
How can I keep all the protocol in variable differently?
No, GetPrivateProfileString does not support multiple sections with the same name and will always use the first one it encounters. There are a couple of straight forward approaches that can be used. The first is to simply append a number to the end of each section name.
[Connection0]
Protocol=HTPP
[Connection1]
Protocol=HTTPS
[Connection2]
Protocol=FTP
[Connection3]
Protocol=Telnet
With this approach you can iterate through the various Connection sections until you try loading one that does not exist.
#include <windows.h>
#include <iostream>
#include <sstream>
int main()
{
for (DWORD i = 0, size = 1; size != 0; ++i)
{
std::ostringstream name;
name << "Connection" << i;
std::string protocol(100, 0);
size = GetPrivateProfileStringA(
name.str().c_str(),
"Protocol",
NULL,
&protocol[0],
protocol.size(),
"./test1.ini");
if (size != 0)
{
protocol.resize(size);
std::cout
<< name.str().c_str()
<< ":protocol=" << protocol << "\n";
}
}
}
Another way is to have a primary section (i.e. Connections) that defines a list of other sections each with a unique name. The benefit to this is that the sections are much easier to manage one one is deleted and eliminates the need to reorder the remaining sections. In this case you can simply rewrite the contents of Connections.
[Connections]
Connection0=HTTPConnection
Connection1=HTTPSConnection
Connection2=FTPConnection
Connection3=TelnetConnection
[HTTPConnection]
Protocol=HTPP
[HTTPSConnection]
Protocol=HTTPS
[FTPConnection]
Protocol=FTP
[TelnetConnection]
Protocol=Telnet
With this approach you iterate over the entries of Connections and then load each individual sections.
#include <windows.h>
#include <iostream>
#include <sstream>
int main()
{
for (DWORD i = 0, size = 1; size != 0; ++i)
{
std::ostringstream name;
name << "Connection" << i;
std::string section(100, 0);
size = GetPrivateProfileStringA(
"Connections",
name.str().c_str(),
NULL,
§ion[0],
section.size(),
"./test1.ini");
if (size != 0)
{
section.resize(size);
std::string protocol(100, 0);
size = GetPrivateProfileStringA(
section.c_str(),
"Protocol",
NULL,
&protocol[0],
protocol.size(),
"./test1.ini");
if (size != 0)
{
protocol.resize(size);
std::cout
<< name.str().c_str()
<< ":"
<< section
<< ":protocol=" << protocol << "\n";
}
}
}
}
Related
I have a c++ program running under Linux Debian 9. I'm doing a simple read() from a file descriptor:
int bytes_read = read(fd, buffer, buffer_size);
Imagine that I want to read some more data from the socket, but I want to skip a known number of bytes before getting to some content I'm interested in:
int unwanted_bytes_read = read(fd, unwanted_buffer, bytes_to_skip);
int useful_bytes = read(fd, buffer, buffer_size);
In Linux, is there a system-wide 'built-in' location that I can dump the unwanted bytes into, rather than having to maintain a buffer for unwanted data (like unwanted_buffer in the above example)?
I suppose what I'm looking for would be (sort of) the opposite of MSG_PEEK in the socket world, i.e. the kernel would purge bytes_to_skip from its receive buffer before the next useful call to recv.
If I were reading from a file then lseek would be enough. But this is not possible if you are reading from a socket and are using scatter/gather I/O, and you want to drop one of the fields.
I'm thinking about something like this:
// send side
int a = 1;
int b = 2;
int c = 3;
struct iovec iov[3];
ssize_t nwritten;
iov[0].iov_base = &a;
iov[0].iov_len = sizeof(int);
iov[1].iov_base = &b;
iov[1].iov_len = sizeof(int);
iov[2].iov_base = &c;
iov[2].iov_len = sizeof(int);
nwritten = writev(fd, iov, 3);
// receive side
int a = -1;
int c = -1;
struct iovec iov[3]; // you know that you'll be receiving three fields and what their sizes are, but you don't care about the second.
ssize_t nread;
iov[0].iov_base = &a;
iov[0].iov_len = sizeof(int);
iov[1].iov_base = ??? <---- what to put here?
iov[1].iov_len = sizeof(int);
iov[2].iov_base = &c;
iov[2].iov_len = sizeof(int);
nread = readv(fd, iov, 3);
I know that I could just create another b variable on the receive side, but if I don't want to, how can I read the sizeof(int) bytes that it occupies in the file but just dump the data and proceed to c? I could just create a generic buffer to dump b into, all I was asking is if there is such a location by default.
[EDIT]
Following a suggestion from #inetknght, I tried memory mapping /dev/null and doing my gather into the mapped address:
int nullfd = open("/dev/null", O_WRONLY);
void* blackhole = mmap(NULL, iov[1].iov_len, PROT_WRITE, MAP_SHARED, nullfd, 0);
iov[1].iov_base = blackhole;
nread = readv(fd, iov, 3);
However, blackhole comes out as 0xffff and I get an errno 13 'Permission Denied'. I tried running my code as su and this doesn't work either. Perhaps I'm setting up my mmap incorrectly?
There's a tl;dr at the end.
In my comment, I suggested you mmap() the /dev/null device. However it seems that device is not mappable on my machine (err 19: No such device). It looks like /dev/zero is mappable though. Another question/answer suggests that is equivalent to MAP_ANONYMOUS which makes the fd argument and its associated open() unnecessary in the first place. Check out an example:
#include <iostream>
#include <cstring>
#include <cerrno>
#include <cstdlib>
extern "C" {
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
}
template <class Type>
struct iovec ignored(void *p)
{
struct iovec iov_ = {};
iov_.iov_base = p;
iov_.iov_len = sizeof(Type);
return iov_;
}
int main()
{
auto * p = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if ( MAP_FAILED == p ) {
auto err = errno;
std::cerr << "mmap(MAP_PRIVATE | MAP_ANONYMOUS): " << err << ": " << strerror(err) << std::endl;
return EXIT_FAILURE;
}
int s_[2] = {-1, -1};
int result = socketpair(AF_UNIX, SOCK_STREAM, 0, s_);
if ( result < 0 ) {
auto err = errno;
std::cerr << "socketpair(): " << err << ": " << strerror(err) << std::endl;
return EXIT_FAILURE;
}
int w_[3] = {1,2,3};
ssize_t nwritten = 0;
auto makeiov = [](int & v){
struct iovec iov_ = {};
iov_.iov_base = &v;
iov_.iov_len = sizeof(v);
return iov_;
};
struct iovec wv[3] = {
makeiov(w_[0]),
makeiov(w_[1]),
makeiov(w_[2])
};
nwritten = writev(s_[0], wv, 3);
if ( nwritten < 0 ) {
auto err = errno;
std::cerr << "writev(): " << err << ": " << strerror(err) << std::endl;
return EXIT_FAILURE;
}
int r_ = {0};
ssize_t nread = 0;
struct iovec rv[3] = {
ignored<int>(p),
makeiov(r_),
ignored<int>(p),
};
nread = readv(s_[1], rv, 3);
if ( nread < 0 ) {
auto err = errno;
std::cerr << "readv(): " << err << ": " << strerror(err) << std::endl;
return EXIT_FAILURE;
}
std::cout <<
w_[0] << '\t' <<
w_[1] << '\t' <<
w_[2] << '\n' <<
r_ << '\t' <<
*(int*)p << std::endl;
return EXIT_SUCCESS;
}
In the above example you can see that I create a private (writes won't be visible by children after fork()) anonymous (not backed by a file) memory mapping of 4KiB (one single page size on most systems). It's then used twice to provide a write destination for two ints -- the later int overwriting the earlier one.
That doesn't exactly solve your question: how to ignore the bytes. Since you're using readv(), I looked into its sister function, preadv() which on first glance appears to do what you want it to do: skip bytes. However, it seems that's not supported on socket file descriptors. The following code gives preadv(): 29: Illegal seek.
rv = makeiov(r_[1]);
nread = preadv(s_[1], &rv, 1, sizeof(int));
if ( nread < 0 ) {
auto err = errno;
std::cerr << "preadv(): " << err << ": " << strerror(err) << std::endl;
return EXIT_FAILURE;
}
So it looks like even preadv() uses seek() under the hood which is, of course, not permitted on a socket. I'm not sure if there is (yet?) a way to tell the OS to ignore/drop bytes received in an established stream. I suspect that's because #geza is correct: the cost to write to the final (ignored) destination is extremely trivial for most situations I've encountered. And, in the situations where the cost of the ignored bytes is not trivial, you should seriously consider using better options, implementations, or protocols.
tl;dr:
Creating a 4KiB anonymous private memory mapping is effectively indistinguishable from contiguous-allocation containers (there are subtle differences that aren't likely to be important for any workload outside of very high end performance). Using a standard container is also a lot less prone to allocation bugs: memory leaks, wild pointers, et al. So I'd say KISS and just do that instead of endorsing any of the code I wrote above. For example: std::array<char, 4096> ignored; or std::vector<char> ignored{4096}; and just set iovec.iov_base = ignored.data(); and set the .iov_len to whatever size you need to ignore (within the length of the container).
The efficient reading of data from a socket is when:
The user-space buffer size is the same or larger (SO_RCVBUF_size + maximum_message_size - 1) than that of the kernel socket receive buffer. You can even map buffer memory pages twice contiguously to make it a ring-buffer to avoid memmoveing incomplete messages to the beginning of the buffer.
The reading is done in one call of recv. This minimizes the number of syscalls (which are more expensive these days due to mitigations for Spectre, Meltdown, etc..). And also prevents starvation of other sockets in the same event loop, which can happen if the code repeatedly calls recv on the same socket with small buffer size until it fails with EAGAIN. As well as guarantees that you drain the entire kernel receive buffer in one recv syscall.
If you do the above, you should then interpret/decode the message from the user-space buffer ignoring whatever is necessary.
Using multiple recv or recvmsg calls with small buffer sizes is sub-optimal with regards to latency and throughput.
I want to access and edit multiple addresses in memory.
In case it's vague, the question is: If I used memory scanner and the results were a list of addresses, how would I be able to access and edit them all?
I've already been told to try putting all the addresses in an array, how do I do this?
Here's the code so far:
//
#include "stdafx.h"
#include "iostream"
#include "Windows.h"
#include <cstdint>
#include <stdint.h>
using namespace std;
int main()
{
int newValue = 0;
int* p;
p = (int*)0x4F6DCFE3DC; // now p points to address 0x220202
HWND hwnd = FindWindowA(NULL, "Call of Duty®: Modern Warfare® 3 Multiplayer");// Finds Window
if (hwnd == NULL) {// Tests for success
cout << "The window is not open" << endl;
Sleep(3000);
exit(-1);
}
else {
cout << "It's open boss!";
}
else {// If Successful Begins the following
DWORD procID;
GetWindowThreadProcessId(hwnd, &procID);
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procID);//Gets handle on process
if (procID == NULL) {
cout << "Cannot obtain process." << endl;
Sleep(3000);
exit(-1);
}
else {//Begins writing to memory
while (newValue == 0) {
/*This Writes*/WriteProcessMemory(handle, (LPVOID)0x04F6DCFE3DC, &newValue, sizeof(newValue), 0);
cout << p;
Sleep(3000);
}
}
}
}
It's fairly easy. Just use a std::vector<std::pair<int*,int>> to contain all these addresses you want to modify along with the value they should achieve:
std::vector<std::pair<int*,int>> changeMap = {
{ (int*)0x4F6DCFE3DC , 0 }
// more address value pairs ...
};
Then you can process them in a loop:
for(auto it = std::begin(changeMap); it != std::end(changeMap); ++it)
{
WriteProcessMemory(handle, (LPVOID)it->first, &(it->second),
sizeof(it->second), 0);
}
Whatever you want to achieve with that1.
I've already been told to try putting all the addresses in an array, how do I do this?
If you want to set all the address contents to 0 you may use a simpler construct:
int newValue = 0;
std::vector<int*> changeAddrList = {
(int*)0x4F6DCFE3DC ,
// more addresses to change ...
};
// ...
for(auto addr : changeAddrList)
{
WriteProcessMemory(handle, (LPVOID)addr , &newValue ,
sizeof(newValue), 0);
}
1Fiddling around in another processes memory is error prone and might lead to all kinds of unexpected behavior!
Your code may fail miserably at a newer version of that program, where you're trying to apply your cheat codez.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am developing a c++ application (in VS2012, Windows Server 2012 R2) that writes large volumes of binary data, from cyclical arrays of buffers that have been allocated, to raw files. The thing is that system RAM usage as reported by Windows Task Manager increases in a linear rate as fwrite writes the data in the files until it reaches a certain point where it remains almost constant (also see the following image). Also, the memory used by my application remains constant the whole time.
I call fflush periodically and it has no effect. Although it seems to be a harmless case, I am concerned about this issue in terms of performance, as another Java application will also be running in a nominal operation.
Therefore, I would like to ask if I should worry about this and if there is a way to avoid this issue towards achieving the best performance for a real-time data recording system.
Similar questions have been asked here and here for linux operating systems and it has been said that the system can devote an amount of memory for caching the data, as long as there is enough memory available.
A part of the application is presented next. In short, the application controls a pair of cameras and each of them acquires frames and store them in properly aligned allocated buffers. There are i) a CameraInterface class, which creates two "producer" threads, ii) a Recorder class, which creates two "consumer" threads and iii) a SharedMemoryManager class that provides a producer with an available buffer for storing data and a consumer with the next buffer to be written to the file. The SharedMemoryManager holds two arrays of buffers (one for each pair of producer-consumer) and two respective arrays of flags that indicate the status of the buffer. It also holds two std::queue objects for quick accessing of the next buffers to be recorder. Parts of the Recorder and the SharedMemoryManager are shown next.
// somewhere in file "atcore.h"...
typedef unsigned char AT_U8;
// File: SharedMemoryManager.h
#ifndef __MEM_MANAGER__
#define __MEM_MANAGER__
#pragma once
#include "atcore.h"
#include <queue>
#include <mutex>
#define NBUFFERS 128
#define BUFFER_AVAILABLE 0
#define BUFFER_QUEUED 1
#define BUFFER_FULL 2
#define BUFFER_RECORDING_PENDING 3
// the status flag cycle is
// EMPTY -> QUEUED -> FULL -> RECORDING_PENDING -> EMPTY
using namespace std;
typedef struct{
AT_U8** buffers;
int* flags;
int acquiredCounter;
int consumedCounter;
int queuedCounter;
mutex flagMtx;
} sharedMemory;
typedef struct{
AT_U8* buffer;
int bufSize;
int index;
} record;
class SharedMemoryManager
{
public:
SharedMemoryManager();
~SharedMemoryManager(void);
void enableRecording();
void disableRecording();
int setupMemory(int cameraIdentifier, int bufferSize);
void freeMemory();
void freeCameraMemory(int cameraIdentifier);
int getBufferSize(int cameraIdentifier);
AT_U8* getBufferForCameraQueue(int cameraIdentifier); // get pointer to the next available buffer for queueing in the camera
int hasFramesForRecording(int cameraIdentifier); // ask how many frames for recording are there in the respective queue
AT_U8* getNextFrameForRecording(int cameraIdentifier); // get pointer to the next buffer to be recorded to a file
void copyMostRecentFrame(unsigned char* buffer, int cameraIdentifier); // TODO // get a copy of the most recent frame on the buffer
void notifyAcquiredFrame(AT_U8* buffer, int bufSize, int cameraIdentifier); // use this function to notify the manager that the buffer has just been filled with data
void notifyRecordedFrame(AT_U8* buffer, int cameraIdentifier); // use this function to notify the manager that the buffer has just been written to file and can be used again
private:
bool useMem0, useMem1;
int bufSize0, bufSize1;
sharedMemory* memory0;
sharedMemory* memory1;
queue<record*> framesForRecording0;
queue<record*> framesForRecording1;
bool isRecording;
int allocateBuffers(sharedMemory* mem, int bufSize);
void freeBufferArray(sharedMemory* mem);
};
#endif // !__MEM_MANAGER
// File: SharedMemoryManager.cpp
...
int SharedMemoryManager::hasFramesForRecording(int cameraIdentifier){
if (cameraIdentifier!=0 && cameraIdentifier!=1){
cout << "Could not get the number of frames in the shared memory. Invalid camera id " << cameraIdentifier << endl;
return -1;
}
if (cameraIdentifier==0){
return (int)framesForRecording0.size();
}
else{
return (int)framesForRecording1.size();
}
}
AT_U8* SharedMemoryManager::getNextFrameForRecording(int cameraIdentifier){
if (cameraIdentifier!=0 && cameraIdentifier!=1){
cout << "Error in getNextFrameForRecording. Invalid camera id " << cameraIdentifier << endl;
return NULL;
}
sharedMemory* mem;
if (cameraIdentifier==0) mem=memory0;
else mem=memory1;
queue<record*>* framesQueuePtr;
if (cameraIdentifier==0) framesQueuePtr = &framesForRecording0;
else framesQueuePtr = &framesForRecording1;
if (framesQueuePtr->empty()){ // no frames to be recorded at the moment
return NULL;
}
record* item;
int idx;
AT_U8* buffer = NULL;
item = framesQueuePtr->front();
framesQueuePtr->pop();
idx = item->index;
delete item;
mem->flagMtx.lock();
if (mem->flags[idx] == BUFFER_FULL){
mem->flags[idx] = BUFFER_RECORDING_PENDING;
buffer = mem->buffers[idx];
}
else{
cout << "PROBLEM. Buffer in getBufferForRecording. Buffer flag is " << mem->flags[idx] << endl;
cout << "----- BUFFER FLAGS -----" << endl;
for (int i=0; i<NBUFFERS; i++){
cout << "[" << i << "] " << mem->flags[i] << endl;
}
cout << "----- -----" << endl;
}
mem->flagMtx.unlock();
return buffer;
}
int SharedMemoryManager::allocateBuffers(sharedMemory* mem, int bufSize){
// allocate the array for the buffers
mem->buffers = (AT_U8**)calloc(NBUFFERS,sizeof(AT_U8*));
if (mem->buffers==NULL){
cout << "Could not allocate array of buffers." << endl;
return -1;
}
// allocate the array for the respective flags
mem->flags = (int*)malloc(NBUFFERS*sizeof(int));
if (mem->flags==NULL){
cout << "Could not allocate array of flags for the buffers." << endl;
free(mem->buffers);
return -1;
}
int i;
for (i=0; i<NBUFFERS; i++){ // allocate the buffers
mem->buffers[i] = (AT_U8*)_aligned_malloc((size_t)bufSize,8);
if (mem->buffers[i] == NULL){
cout << "Could not allocate memory for buffer no. " << i << endl;
for (int j=0; j<i; j++){ // free the previously allocated buffers
_aligned_free(mem->buffers[j]);
}
free(mem->buffers);
free(mem->flags);
return -1;
}
else{
mem->flags[i]=BUFFER_AVAILABLE;
}
}
return 0;
}
void SharedMemoryManager::freeBufferArray(sharedMemory* mem){
if (mem!=NULL){
for(int i=0; i<NBUFFERS; i++){
_aligned_free(mem->buffers[i]);
mem->buffers[i]=NULL;
}
free(mem->buffers);
mem->buffers = NULL;
free(mem->flags);
mem->flags = NULL;
free(mem);
mem = NULL;
}
}
// File: Recorder.h
#ifndef __RECORDER__
#define __RECORDER__
#pragma once
#include <string>
#include <queue>
#include <future>
#include <thread>
#include "atcore.h"
#include "SharedMemoryManager.h"
using namespace std;
class Recorder
{
public:
Recorder(SharedMemoryManager* memoryManager);
~Recorder();
void recordBuffer(AT_U8 *buffer, int bufsize);
int setupRecording(string filename0, string filename1, bool open0, bool open1);
void startRecording();
void stopRecording();
int testWriteSpeed(string directoryPath, string filename);
void insertFrameItem(AT_U8* buffer, int bufSize, int chunkID);
private:
FILE *chunk0, *chunk1;
string chunkFilename0, chunkFilename1;
int frameCounter0, frameCounter1;
bool writes0, writes1;
int bufSize0, bufSize1;
static SharedMemoryManager* manager;
bool isRecording;
promise<int> prom0;
promise<int> prom1;
thread* recordingThread0;
thread* recordingThread1;
static void performRecording(promise<int>* exitCode, int chunkIdentifier);
void writeNextItem(int chunkIdentifier);
void closeFiles();
};
#endif //!__RECORDER__
// File: Recorder.cpp
#include "Recorder.h"
#include <ctime>
#include <iostream>
using namespace std;
Recorder* recorderInstance; // keep a pointer to the current instance, for accessing static functions from (non-static) objects in the threads
SharedMemoryManager* Recorder::manager; // the same reason
...
void Recorder::startRecording(){
if (isRecording == false){ // do not start new threads if some are still running
isRecording = true;
if (writes0==true) recordingThread0 = new thread(&Recorder::performRecording, &prom0, 0);
if (writes1==true) recordingThread1 = new thread(&Recorder::performRecording, &prom1, 1);
}
}
void Recorder::writeNextItem(int chunkIdentifier){
FILE* chunk;
AT_U8* buffer;
int* bufSize;
if (chunkIdentifier==0){
chunk = chunk0;
bufSize = &bufSize0;
buffer = manager->getNextFrameForRecording(0);
}
else {
chunk = chunk1;
bufSize = &bufSize1;
buffer = manager->getNextFrameForRecording(1);
}
size_t nbytes = fwrite(buffer, 1, (*bufSize)*sizeof(unsigned char), chunk);
if (nbytes<=0){
cout << "No data were written to file." << endl;
}
manager->notifyRecordedFrame(buffer,chunkIdentifier);
if (chunkIdentifier==0) frameCounter0++;
else frameCounter1++;
}
void Recorder::performRecording(promise<int>* exitCode, int chunkIdentifier){
bool flag = true;
int remaining = manager->hasFramesForRecording(chunkIdentifier);
while( recorderInstance->isRecording==true || remaining>0 ){
if (remaining>0){
if (recorderInstance->isRecording==false){
cout << "Acquisition stopped, still " << remaining << " frames are to be recorded in chunk " << chunkIdentifier << endl;
}
recorderInstance->writeNextItem(chunkIdentifier);
}
else{
this_thread::sleep_for(chrono::milliseconds(10));
}
remaining = manager->hasFramesForRecording(chunkIdentifier);
}
cout << "Done recording." << endl;
}
In the Windows memory use screen shot you show, the biggest chunk (45GB) is "cached" of which 27GB is "modified", meaning "dirty pages waiting to be written to disk". This is normal behavior because you are writing faster than the disk I/O can keep up. flush/fflush has no effect on this because it is not in your process. As you note: "the memory used by my application remains constant the whole time". Do not be concerned. However, if you really don't want the OS to buffer dirty output pages, consider using "unbuffered I/O" available on Windows, as it will write through immediately to disk.
Edit: Some links to unbuffered I/O on Windows. Note that unbuffered I/O places memory-alignment constraints on your reads and writes.
File Buffering
CreateFile function
I am having a bit of trouble getting a System V Message Queue setup and working properly on Linux. The idea is to get a central node to pull data from several other nodes. The trouble is that the central node ends up sitting there waiting for the other nodes to send messages. I have looked at the values for the mailboxes and they are the same across all processes. I.E. 0 for the central mailbox, 32769 for other process 1, ect. I have no idea on why it appears to fail. I have tried to change the priority parameter in msgrcv to 0 to accept all incoming messages and the same issue occurs. Any help would be much appriciated. (Sorry for the lack of comments.)
Here is the code for the central node:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <iostream>
struct{
long priority;
int temperature;
int pid;
int stable;
} msgp;
const int mainMailID = 8484;
using namespace std;
int main(int argc, char* argv[]){
//declare needed variables
int centralMailID;
int externalMailID[4];
int tempdata;
int externalTempature[4];
int externalTemperatureLast[4];
//set initial values for msgp
msgp.priority = 2;
msgp.temperature = atoi(argv[1]);
msgp.pid = 0;
msgp.stable = 0;
//create the central mailbox
centralMailID = msgget(mainMailID, 0600 | IPC_CREAT);
if(centralMailID == -1){
cout << "Message Queue Creation Failed" << endl;
}
else{
cout << "Message Queue Created" << endl;
}
//create the external mailboxes
for(int i = 0; i < 4 ; i++){
externalMailID[i] = msgget(mainMailID + i+1, 0600 | IPC_CREAT);
if(externalMailID[i] == -1){
cout << "Message Queue " << i << " Creation Failed" << endl;
}
else{
cout << "Message Queue " << i << " Created" << endl;
}
}
printf("%i", externalMailID[0]);
while(msgp.stable == 0){
int centralTemperature = msgp.temperature;
//get the tempatures from the external sensors.
for(int i = 0; i<4; i++){
tempdata = msgrcv(externalMailID[i], &msgp, sizeof(msgp)-sizeof(long), 2, 0);
cout << "Recived data from sensor " << msgp.pid << endl;
externalTempature[i] = msgp.temperature;
}
if(externalTempature[0] == externalTempature[1] == externalTempature[2] == externalTempature[3] == centralTemperature){
msgp.stable = 1;
continue; //could also use break
}
int sum = 0;
for(int i = 0; i<4; i++){
sum = sum + externalTempature[i];
}
centralTemperature = ((2 * centralTemperature) + sum)/6;
msgp.temperature = centralTemperature;
for(int i = 0; i<4; i++){
tempdata = msgsnd(externalMailID[i], &msgp, sizeof(msgp)-sizeof(long), 0);
printf("Sent data to external mailbox %i", i);
}
}
printf("Process ended");
return 0;
}
Here is the code for the other nodes:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <iostream>
struct{
long priority;
int temperature;
int pid;
int stable;
} msgp;
const int mainMailID = 8484;
using namespace std;
int main(int argc, char* argv[]){
int centralMailID = msgget(mainMailID, 0600 | IPC_CREAT);
int pid = atoi(argv[2]);
int externalMailID = msgget(mainMailID + pid, 0600 | IPC_CREAT);
int externalTemperature = atoi(argv[1]);
int tempdata;
cout << externalMailID << endl;
msgp.priority = 2;
msgp.pid = pid;
msgp.stable = 0;
while(msgp.stable == 0){
msgp.temperature = externalTemperature;
tempdata = msgsnd(centralMailID, &msgp, sizeof(msgp)-sizeof(long), 0);
tempdata = msgrcv(externalMailID, &msgp, sizeof(msgp)-sizeof(long), 2, 0);
externalTemperature = ((externalTemperature * 3) + (msgp.temperature * 2))/5;
if(msgp.stable == 1){
continue;
}
}
printf("Child Process Ended");
return 0;
}
You're using the system V api, which is probably not what you want. See here for more details:
http://mij.oltrelinux.com/devel/unixprg/#ipc__posix_msgqs
The msgget, msgctl, msgsnd, msgrcv commands are part of the older, system V api, and while the semantics are similar, are not posix queues. A couple of quick google search for system V queue tutorials/examples are likely to solve your problem.
If you're genuinely looking to use posix queues, switch to and look for documentation on the mq_open, mq_close, mq_unlink, mq_send, mq_receive, mq_getattr, mq_setattr api.
I am building a client that:
Should be able to recieve information from both the server and the standart input
Should be able to recieve information from the server without asking, for example when another client sends a message.
To do so I tried using select to monitor both possible inputs.
What happens is that when a keyboard input is monitored I send a message to the client and I expect one back, so there's no problem. But when the server sends an unexpected message nothing happens, and I don't know why. Is using select() the proper way to do so? Is it even possible to use select() without listen()ing?
Here's my code (compileable):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <cstring>
#include <arpa/inet.h>
#include <iostream>
#include <fstream>
#define MAX_CLIENT_NAME 30
#define MAX_TWIT_SIZE 140
#define NUM_OF_ARG 4
#define ERROR -1
#define GREAT_SUCCESS 0
#define OK "OK"
#define EXIT "EXIT"
using std::string;
using std::cerr;
using std::endl;
using std::cout;
string clientName;
int srverfd, numbytes, status, maxSock ;
fd_set inputFdSet; /* Socket file descriptors we want to wake
up for, using select() */
int establishConnection(char * serverAddress,char * port){
if ((srverfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
return ERROR;
}
struct sockaddr_in server;
server.sin_family = AF_INET;
inet_aton(serverAddress, &server.sin_addr);
server.sin_port = htons(atoi(port));
memset(&(server.sin_zero), '\0', 8);
if (connect(srverfd,(const struct sockaddr *)&server,sizeof(struct sockaddr)) == -1) {
perror("connect");
close(srverfd);
return ERROR;
}
maxSock = srverfd;
return GREAT_SUCCESS;
}
const char * getUserTweet(){
string temp;
getline(std::cin,temp);
return temp.c_str();
}
void sendMessage(string message){
if ((numbytes = send(srverfd, message.c_str(), message.length(), 0)) == -1) {
perror("sendMessage");
close(srverfd);
}
cout<<"Message sent: "<< message << endl;
return;
}
const char * getMessage(){
char buf[MAX_TWIT_SIZE];
memset(buf,'\0',MAX_TWIT_SIZE);
if ((numbytes = recv(srverfd, buf, 140, 0)) == -1) {
perror("getMessage");
close(srverfd);
}
string temp = buf;
return temp.c_str();
}
void build_select_list() {
FD_ZERO(&inputFdSet);
FD_SET(srverfd,&inputFdSet);
FD_SET(STDIN_FILENO,&inputFdSet);
if (STDIN_FILENO > maxSock)
maxSock = STDIN_FILENO;
return;
}
void readSocket(fd_set tempfd) {
const char * tweet, * inMessage;
if (FD_ISSET(srverfd,&tempfd)) {
inMessage = getMessage();
cout << inMessage << endl;
}
if (FD_ISSET(STDIN_FILENO,&tempfd)) {
tweet = getUserTweet();
sendMessage(tweet);
inMessage = getMessage();
if (strcmp(inMessage,OK) != 0) {
cout << inMessage << endl;
}
if (strcmp(inMessage,EXIT) == 0) {
return;
}
}
return;
}
int main (int argc, char *argv[] ){
int value;
bool clientON = false;
if(establishConnection(argv[2],argv[3])){
cerr << "usage: failed to make connection" << endl << "exiting..." << endl;
exit(EXIT_FAILURE);
}
cout << "Connected successfully" << endl;
sendMessage("CONNECT "+clientName); //Connect
if(strcmp(getMessage(),OK) == 0){
clientON = true;
}
while(clientON){
build_select_list();
value = select(maxSock, &inputFdSet, NULL, NULL, NULL);
if (value < 0) {
perror("select");
exit(EXIT_FAILURE);
}
if (value == 0) {
continue;
}
else {
readSocket(inputFdSet);
}
}
sendMessage("DISCONNECT");
if(strcmp(getMessage(),OK) == 0){
// do nothing
}
close(srverfd);
return 0;
}
Your select call is invalid. The first parameter must be the highest file descriptor in any of the sets, plus one.
As you have it, an event on srverfd will not "wake up" the select call (unless STDIN_FILENO was somehow less than srverfd, in which case stdin events wouldn't unlock select - but that won't happen in practice).
There are quite a few other problems with your code. (It doesn't really look like C++.)
getUserTweet is unreliable (undefined behavior - temp is destroyed as soon as the function returns, so the char* you return has disappeared by the time its caller will try to use it). Same for getMessage. To remedy that, use std::string everywhere, and only extract the char* when you call into C library functions).
readSocket needlessly copies the FD set (can be expensive).
You should really get rid of all those globals - build one or two classes to encapsulate that state and the networking functions, or something like that.