So, I am writing a small winsock app and I need to make a multi-client server.
I decided to use threads for every new connection, the problem is that I don't know how to pass multiple data to a thread, so I use struct.
Struct:
typedef struct s_par {
char lttr;
SOCKET clientSocket;
} par;
_stdcall:
unsigned __stdcall ClientSession(void *data) {
par param = data;
char ch = param.lttr;
SOCKET clntSocket = param.clientSocket;
// ..working with client
}
Main:
int main() {
unsigned seed = time (0);
srand(seed);
/*
..........
*/
SOCKET clientSockets[nMaxClients-1];
char ch = 'a' + rand()%26;
while(true) {
cout << "Waiting for clients(MAX " << nMaxClients << "." << endl;
while ((clientSockets[nClient] = accept(soketas, NULL, NULL))&&(nClient < nMaxClients)) {
par param;
// Create a new thread for the accepted client (also pass the accepted client socket).
if(clientSockets[nClient] == INVALID_SOCKET) {
cout << "bla bla" << endl;
exit(1);
}
cout << "Succesfull connection." << endl;
param.clientSocket = clientSockets[nClient];
param.lttr = ch;
unsigned threadID;
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &ClientSession, ¶m, 0, &threadID);
nClient++;
}
The problem is that I get errors with data type conversion. Maybe someone could suggest an easy fix with passing this struct to a thread?
With each round of your while-loop you're doing two ill-advised activites:
Passing the address of an automatic variable that will be destroyed with each cycle of the loop.
Leaking a thread HANDLE returned from _beginthreadex
Neither of those is good. Ideally your thread proc should look something like this:
unsigned __stdcall ClientSession(void *data)
{
par * param = reinterpret_cast<par*>(data);
char ch = param->lttr;
SOCKET clntSocket = param->clientSocket;
// ..working with client
delete param;
return 0U;
}
And the caller side should do something like this:
par *param = new par;
param->clientSocket = clientSockets[nClient];
param->lttr = ch;
...
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &ClientSession, param, 0, &threadID);
if (hThread != NULL)
CloseHandle(hThread);
else
delete param; // probably report error here as well
That should be enough to get you going. I would advise you may wish to take some time to learn about the C++11 Threading Model. It makes much of this considerably more elegant (and portable!).
Best of luck.
Related
I'm doing my first practice with message queues. I want mq_receive to block so I do not have O_NOBLOCK turned on.
The mq_receive method is returning, and perror() is printing "message too long". This is before I've even sent the message.
The ATM sends the messages:
void* run_ATM(void* arg) {
int status;
char accountNumber[15];
cout << "ATM is running" << endl;
cout << "Please input an account number > ";
cin >> accountNumber;
status = mq_send(PIN_MSG, accountNumber, sizeof(accountNumber), 1);
}
The database receives them
void* run_DB(void* arg){
cout << "Database server running" << endl;
int status;
char received_acct_number[30];
while(1){
status = mq_receive(PIN_MSG, received_acct_number, 100, NULL);
if (status < 0){
perror("error ");
} else {
cout << "received account number\t" << received_acct_number << endl;
}
}
}
This is just preliminary code - so it will eventually do more. I just wanted to get a basic working example.
EDIT: other code required to get this to run:
#define PIN_MSG_NAME "/pin_msg"
#define DB_MSG_NAME "/db_msg"
#define MESSAGE_QUEUE_SIZE 15
pthread_t ATM;
pthread_t DB_server;
pthread_t DB_editor;
void* run_ATM(void* arg);
void* run_DB(void* arg);
static struct mq_attr mq_attribute;
static mqd_t PIN_MSG, DB_MSG;
int main(int argc, char const *argv[])
{
pthread_attr_t attr;
mq_attribute.mq_maxmsg = 10; //mazimum of 10 messages in the queue at the same time
mq_attribute.mq_msgsize = MESSAGE_QUEUE_SIZE;
PIN_MSG = mq_open(PIN_MSG_NAME, O_CREAT | O_RDWR, 0666, &mq_attribute);
DB_MSG = mq_open(DB_MSG_NAME, O_CREAT | O_RDWR, 0666, &mq_attribute);
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 1024*1024);
long start_arg = 0; //the start argument is unused right now
pthread_create(&ATM, NULL, run_ATM, (void*) start_arg);
pthread_create(&DB_server, NULL, run_DB, (void*) start_arg);
pthread_join(ATM, NULL);
pthread_join(DB_server, NULL);
}
The receiving buffer is larger than the message queue size, so there should be no issues, right?
If you checked for error returns from functions and printed them, the error would be obvious. You are casting the values of accountNumber and PIN to pointers rather than casting their addresses. You want:
status = mq_send(PIN_MSG, (const char*) &accountNumber, MESSAGE_QUEUE_SIZE, 1);
status = mq_send(PIN_MSG, (const char*) &PIN, MESSAGE_QUEUE_SIZE, 1);
status = mq_receive(PIN_MSG, (char*) &received_acct_number, 100, NULL);
status = mq_receive(PIN_MSG, (char*) &received_PIN, MESSAGE_QUEUE_SIZE, NULL);
Note that there are still a lot of problems with our code, most notably the fact that you overrun these variables by not correctly processing their sizes. You can sort of fix that like this:
status = mq_send(PIN_MSG, (const char*) &accountNumber, sizeof (accountNumber), 1);
status = mq_send(PIN_MSG, (const char*) &PIN, sizeof (PIN), 1);
status = mq_receive(PIN_MSG, (char*) &received_acct_number, sizeof(received_acct_number), NULL);
status = mq_receive(PIN_MSG, (char*) &received_PIN, sizeof(received_PIN), NULL);
But really you should have some kind of message format and you should serialize your messages to and from that format.
So it looks like the main issue was with a leftover message queue, since they are not properly closed/unlinked in the code.
There were some bugs in my original code, and I appreciate the answers that pointed that out and gave me solutions.
The issue comes when trying to change the format of the message, I guess when mq_open is called again, it doesn't change the message size (since the message queue already exists). This leads to size errors in the code. Rebooting is a workaround, but the solution is to properly clean up with mq_unlink() and then mq_close()
So I am writing a Windows chat and for testing purposes my client program sends a "hello" message to the server every 300 ms.
First couple messages come good but then like for no reason they start to become junk-
Obviously I want to fix it and I seek for your help :) Here is my code:
Send function:
bool Target::Send(char *message)
{
int length = strlen(message);
int result = send(this->ccSock, (char*)&length, sizeof(int), 0);
if (result <= 0)
return false;
Sleep(10);
result = send(this->ccSock, message, length, 0);
return ((result > 0) ? true : false);
}
Receive function:
Message Server::Receive(SOCKET socket)
{
int length = 0;
int result = recv(socket, (char*)&length, sizeof(int), 0);
Sleep(10);
char *rcvData = new char[length];
result = recv(socket, rcvData, length, 0);
return { rcvData, result };
}
Message struct:
struct Message {
char *msg;
int size;
};
Main send code:
while (true)
{
if (!target->Send("hello"))
{
cout << "Connection broken\n";
target->Clean();
break;
}
Sleep(300);
}
Main receive code:
while (target.sock)
{
Message message = server->Receive(target.sock);
if (message.size > 0)
cout << message.msg << " (" << message.size << ")\n";
else
{
cout << "Target disconnected\n";
server->Clean();
break;
}
Sleep(1);
}
I would really appreciate your help as well as explanation why this is happening!
Your buffer is not null terminated. So when you are trying to print it using std::cout buffer overrun occurs. Correct version of receive code should be:
char *rcvData = new char[length+1];
result = recv(socket, rcvData, length, 0);
rcvData[length] = '\0';
Also you never free allocated memory buffer, so your code leaks it on each Receive call.
I need some algorithm help with a multithreaded program I'm writing. It's basically the cp command in unix, but with a read thread and a write thread. I'm using semaphores for thread synchronization. I have structs for buffer and thread data defined as
struct bufType {
char buf[BUFFER_SIZE];
int numBytes;
};
struct threadData {
int fd;
bufType buf;
};
and a global array of bufType. Code for my main is
int main(int argc, const char * argv[])
{
int in, out;
pthread_t Producer, Consumer;
threadData producerData, consumerData;
if (argc != 3)
{
cout << "Error: incorrect number of params" << endl;
exit(0);
}
if ((in = open(argv[1], O_RDONLY, 0666)) == -1)
{
cout << "Error: cannot open input file" << endl;
exit(0);
}
if ((out = open(argv[2], O_WRONLY | O_CREAT, 0666)) == -1)
{
cout << "Cannot create output file" << endl;
exit(0);
}
sem_init(&sem_empty, 0, NUM_BUFFERS);
sem_init(&sem_full, 0, 0);
pthread_create (&Producer, NULL, read_thread, (void *) &producerData);
pthread_create (&Consumer, NULL, write_thread, (void *) &consumerData);
pthread_join(Producer, NULL);
pthread_join(Consumer, NULL);
return 0;
}
and read and write threads:
void *read_thread(void *data)
{
threadData *thread_data;
thread_data = (threadData *) data;
while((thread_data->buf.numBytes = slow_read(thread_data->fd, thread_data->buf.buf, BUFFER_SIZE)) != 0)
{
sem_post(&sem_full);
sem_wait(&sem_empty);
}
pthread_exit(0);
}
void *write_thread(void *data)
{
threadData *thread_data;
thread_data = (threadData *) data;
sem_wait(&sem_full);
slow_write(thread_data->fd, thread_data->buf.buf, thread_data->buf.numBytes);
sem_post(&sem_empty);
pthread_exit(0);
}
So my issue is in what to assign to my threadData variables in main, and my semaphore logic in the read and write threads. I appreciate any help you're able to give
Being a windows guy who does not use file descriptors I might be wrong with the in's and out's but I think this needs to be done in your main in order to setup the threadData structures.
producerData.fd = in;
consumerData.fd = out;
Then declare ONE SINGLE object of type bufType for both structures. Change for example the definition of threadData to
struct threadData {
int fd;
bufType* buf;
};
and in your Main, you write
bufType buffer;
producerData.buf = &buffer;
consumerData.buf = &buffer;
Then both threads will use a common buffer. Otherwise you would be writing to the producerData buffer, but the consumerData buffer will stay empty (and this is where your writer thread is looking for data)
Then you need to change your signalling logic. Right now your program cannot accept input that exceeds BUFFER_SIZE, because your write thread will only write once. There needs to be a loop around it. And then you need some mechanism that signals the writer thread that no more data will be sent. For example you could do this
void *read_thread(void *data)
{
threadData *thread_data;
thread_data = (threadData *) data;
while((thread_data->buf->numBytes = slow_read(thread_data->fd, thread_data->buf->buf, BUFFER_SIZE)) > 0)
{
sem_post(&sem_full);
sem_wait(&sem_empty);
}
sem_post(&sem_full); // Note that thread_data->buf->numBytes <= 0 now
pthread_exit(0);
}
void *write_thread(void *data)
{
threadData *thread_data;
thread_data = (threadData *) data;
sem_wait(&sem_full);
while (thread_data->buf->numBytes > 0)
{
slow_write(thread_data->fd, thread_data->buf->buf, thread_data->buf->numBytes);
sem_post(&sem_empty);
sem_wait(&sem_full);
}
pthread_exit(0);
}
Hope there are no more errors, did not test solution. But the concept should be what you were asking for.
You could use a common buffer pool, either a circular array or a linked lists. Here is a link to a zip of a Windows example that is similar to what you're asking, using linked lists as part of a inter-thread messaging system to buffer data. Other than the creation of the mutexes, semaphores, and the write thread, the functions are small and simple. mtcopy.zip .
ok so I have a thread that is meant to add to a vector of players but whenever I call the push_back function I get a memory access violations, I've taken out all other code where the vector is being used outside of this thread.
I can read the size of the vector before this happens but I just cannot push_back into it.
the vector looks like this:
std::vector<A_Player> &clientsRef;
adn the thread that it is in is:
void NetworkManager::TCPAcceptClient(){
std::cout << "Waiting to accept that client that pinged us" << std::endl;
fd_set fd;
timeval tv;
FD_ZERO(&fd);
FD_SET(TCPListenSocket, &fd);
tv.tv_sec = 5;//seconds
tv.tv_usec = 0;//miliseconds
A_Player thePlayer;
thePlayer.sock = SOCKET_ERROR;
if (select(0, &fd, NULL, NULL, &tv) > 0){ //using select to allow a timeout if the client fails to connect
if (thePlayer.sock == SOCKET_ERROR){
thePlayer.sock = accept(TCPListenSocket, NULL, NULL);
}
thePlayer.playerNumber = clientsRef.size() + 1;
thePlayer.isJumping = false;
thePlayer.X = 0;
thePlayer.Y = 0;
thePlayer.Z = 0;
clientsRef.push_back(thePlayer);
clientHandler = std::thread(&NetworkManager::ClientRecieve, this);
clientHandler.detach();
}
else{
std::cout << "Client connection timed out!!!!!" << std::endl;
}
}
Can anyone give me some insight into why this doesn't work?
Kind regards
My psychic debugging skills tell me that your clientsRef reference is referencing a destroyed local vector. Take a look at the code where you set the reference.
I found that referencing wouldn't work for the problem I had and I converted it to a pointer system which worked fine.
I'm trying to share a pointer of defined class between the parent and the forked child through shared memory.
so in parent's main i create the pointer
mydata *p;
Reader::GetInstance()->Read(p, i+1);
pid = fork();
if (pid == -1){
cout << "error on fork"<<endl;
}else if (pid == 0){
cout << "i will fork now" <<endl;
const char * path = "./mydatamanager";
execl (path, "-", (char *)0);
break;
}else {
writer(shmid, p);
}
writer contains this
void writer(int shmid , mydata * p)
{
void *shmaddr;
shmaddr = shmat(shmid, (void *)0, 0);
if((int)shmaddr == -1)
{
perror("Error in attach in writer");
exit(-1);
}
else
{
memcpy( shmaddr, p, sizeof(*p) );
}
}
and my data is
class mydara {
public:
int var1;
int var2;
int var3;
int var4;
int var5;
int var6;
char *var7;
mydata (int v2, int v3,char *v7, int v6){
var2 = v2;
var3 = v3;
var7 =new char[128];
strcpy(var7, v7);
var6 = v6;
var4 = 0;
var5 = 0;
}
};
and in the mydatamanager i get this pointer this way
void reader(int shmid, mydata *& p)
{
cout << "in reader" << endl;
void *shmaddr;
//sleep(3);
shmaddr = shmat(shmid, (void *)0, SHM_RDONLY|0644);
if((int)shmaddr == -1)
{
perror("Error in reader");
exit(-1);
}
else
{
cout << "in else "<< endl;
p = (mydata*) shmaddr;
cout <<"shared memory address is " <<shmaddr <<endl;
cout <<"var5 "<< p->var5<< endl;
cout <<"var2 "<< p->var2<< " match with "<<getpid() << "?" << endl;
cout <<"var3 "<< p->var3<< endl;
cout <<"var4 "<< p->var4<< endl;
cout <<"var7 "<< p->var7<< endl; // the
//shmdt(shmaddr);
}
}
and mydatamanager main :
int main()
{
cout << "in main" <<endl;
int shmid;
shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT|0644);
cout << "in advanced point" <<endl;
sleep(1);
mydata * p;
reader (shmid, p);
cout << p->var7 <<endl;
return 0;
}
the results are always 0.
how can i share this pointer through the parent and the child and where is the fault in my code?
Hi i had a IPC task some weeks ago and finally decided to use boost.
http://blog.wolfgang-vogl.com/?p=528
http://www.boost.org/doc/libs/1_36_0/doc/html/interprocess/synchronization_mechanisms.html#interprocess.synchronization_mechanisms.semaphores.semaphores_interprocess_semaphores
First of all, you are not synchronising anything. So how do you know which runs first, the reader or the writer. Memory is bound to be zero in a newly allocated block, so hence you get zero as a result.
Any shared memory must ensure that the reader doesn't read until the writer has completed (at least part of) the writing process, at the very least.
Beware of sharing classes - you must not use virtual functions, as that will almost certainly do something ohterthan what you expect (crash, most likely, but other options are available, none of them particularly pleasant)
The simplest way to handle your problem is to create a semaphore in the parent process before the fork, have the child process try to acquire it before the read (instead of doing a sleep) and the parent process release it after the write.
First, here's functions to create, destroy, and retreive the id of the semaphore:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int create_semaphore(const char *path, char id, int count){
key_t k = ftok(path, id);
semid = semget(k, 1, IPC_CREAT | IPC_EXCL | 0600);
semctl(semid, 0, SET_VAL, count);
return semid;
}
int destroy_semaphore(int semid){
semctl(semid, 0, IPC_RMID, 0);
}
int get_semaphore(const char *path, char id){
key_t k = ftok(path, id);
semid = semget(k, 1, 0600);
return semid;
}
Now we need a function to acquire it, and another one to release it:
void acquire_semaphore(int semid){
sembuf op;
op.sem_num = O;
op.sem_op = -1;
op.sem_flg = 0;
semop(semid,&op,1);
}
void release_semaphore(int semid){
sembuf op;
op.sem_num = 0;
op.sem_op = 1;
op.sem_flg = 0;
semop(semid,&op,1);
}
With these boilerplate functions in place, you should be able to synchronize your processes.
So, you will need to provide a path and a unique id (in the form of a simple character) to create and identify your semaphore. If you already used ftok to create your shared memory id (shmid), you should understand the idea. Otherwise, just make sure that both values are the same within both processes.
In your writer code, put the following line:
semid = create_semaphore(argv[0], 'S', 0);
right before the pid = fork(); line, to create and acquire the semaphore at the same time.
Add the line:
release_semaphore(semid);
after the writer(shmid, mydata); instruction to release the semaphore. You will also need to declare semid somewhere in scope. I used the writer program path to create the semaphore, which is good practice to ensure that no other process has already used our path. The only catch is that you need to make sure that reader will use that same path. You can hardcode that value somewhere in reader's code, or better yet, pass it from writer in the execl parameters (left as an exercise).
Assuming that path is known in reader, all is left to do is to acquire the the semaphore likeso:
semid = get_semaphore(path, 'S');
acquire_semaphore(semid);
destroy_semaphore(semid);
before the line reader(shmid, mydata); in the main function of reader.
As other posts have said, sharing class instances through a shared memory segment is usually a very bad idea. It is much safer
to pass simple struct data, and reconstruct your object on the reader side (look up serialization and marshalling on the net for more information).
Ask if you have problems with this (untested) code.
Merry Christmas!