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.
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 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.
I'm having problems with getting winsock RIO working.
It seems that every time I post a RIOReceive it returns immediately with 0 bytes transferred, and my peer can't get a message through.
After posting a RIOReceive, I wait on the RIODequeCompletion, which deques immediately with numResults = 1, but when I inspect the bytesTransferred of the RIORESULT struct, it's 0. This tells me that I'm not setting this thing up properly, but I can't find docs or examples that tell me what else I should be doing.
The internet seems to have very little on RIO. I've looked through MSDN, Len Holgate with TheServerFramework, this site, and two GitHub RIO servers.
RIOEchoServer and RIOServer_sm9 are on GitHub, but I can't post more than two links (this is my first question on this site).
This code is just to get things proven. It's currently not set to use the sendCQ, doesn't handle errors well, etc...
Here's the prep work:
void serverRequestThread() {
//init buffers
//register big buffers
recvBufferMain = rio.RIORegisterBuffer(pRecvBufferMain, bufferSize);
sendBufferMain = rio.RIORegisterBuffer(pSendBufferMain, bufferSize);
if (recvBufferMain == RIO_INVALID_BUFFERID) {
cout << "RIO_INVALID_BUFFERID" << endl;
}
if (sendBufferMain == RIO_INVALID_BUFFERID) {
cout << "RIO_INVALID_BUFFERID" << endl;
}
//create recv buffer slice
recvBuffer1.BufferId = recvBufferMain;
recvBuffer1.Offset = 0;
recvBuffer1.Length = 10000;
//create send buffer slice
sendBuffer1.BufferId = sendBufferMain;
sendBuffer1.Offset = 0;
sendBuffer1.Length = 10000;
//completion queue
recvCQ = rio.RIOCreateCompletionQueue(CQsize, NULL);
sendCQ = rio.RIOCreateCompletionQueue(CQsize, NULL);
if (recvCQ == RIO_INVALID_CQ) {
cout << "RIO_INVALID_CQ" << endl;
}
if (sendCQ == RIO_INVALID_CQ) {
cout << "RIO_INVALID_CQ" << endl;
}
//start a loop for newly accept'd socket
while (recvCQ != RIO_INVALID_CQ && sendCQ != RIO_INVALID_CQ) {
//get accept'd socket
struct sockaddr_in saClient;
int iClientSize = sizeof(saClient);
acceptSocket = accept(listenSocket, (SOCKADDR*)&saClient, &iClientSize);
if (acceptSocket == INVALID_SOCKET) {
cout << "Invalid socket" << endl;
printError();
}
//register request queue
requestQueue = rio.RIOCreateRequestQueue(
acceptSocket, //socket
10, //max RECVs on queue
1, //max recv buffers, set to 1
10, //max outstanding sends
1, //max send buffers, set to 1
recvCQ, //recv queue
recvCQ, //send queue
pOperationContext //socket context
);
if (requestQueue == RIO_INVALID_RQ) {
cout << "RIO_INVALID_RQ" << endl;
printError();
}
I now post a RIOReceive:
//start a loop to repin recv buffer for socket
while (acceptSocket != INVALID_SOCKET) {
//pin a recv buffer to wait on data
recvSuccess = rio.RIOReceive(
requestQueue, //socketQueue
&recvBuffer1, //buffer slice
1, //set to 1
RIO_MSG_WAITALL, //flags
0); //requestContext
if (recvSuccess == false) {
cout << "RECV ERROR!!!!!!!!\n";
printError();
}
//wait for recv to post in queue
//std::this_thread::sleep_for(std::chrono::milliseconds(3000));
As soon as I call RIODequeCompletion, it returns 1:
numResults = 0;
while (numResults == 0) numResults = rio.RIODequeueCompletion(recvCQ, recvArray, 10);
if (numResults == RIO_CORRUPT_CQ) {
cout << "RIO_CORRUPT_CQ" << endl;
} else if (numResults == 0) {
cout << "no messages on queue\n";
} else if (numResults > 0) {
but when I inspect the bytesTransferred of the RIORESULT, it's always 0:
if (recvArray[0].BytesTransferred > 0) {
//process results
if (pRecvBufferMain[0] == 'G') {
//set respnose html
strcpy(pSendBufferMain, responseHTTP);
sendSuccess = rio.RIOSend(
requestQueue, //socketQueue
&sendBuffer1, //buffer slice
1, //set to 1
0, //flags
0); //requestContext
} else if (pRecvBufferMain[0] == 'P') {
//process post
} else {
//recv'd a bad message
}
} //end bytesTransferred if statement
//reset everything and post another recv
}//end response if statement
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}//end while loop for recv'ing
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}//end while loop for accept'ing
}// end function
Like I said, I'm probably not using RIOReceive correctly, and/or I'm not setting the correct socket options that I need to (none right now).
I appreciate any help with this.
Try removing RIO_MSG_WAITALL. There may be a bug whereby you're only getting the close notification (bytes == 0) rather than getting a completion with the data in it. Either way it would be interesting to see if the code works without the flag.
Do my example servers and tests work on your hardware?
I encountered a similar issue of having zero bytesReceived in my dequeued completion result while using RioReceive with RioNotify and RioDequeueCompletion. I would also see the 'Status' value of WSAEINVAL (Invalid Parameter = 10022) in my dequeued completion result, this seems to indicate the WSA error code for the Receive call.
The particular reason I had the error is because I had allocated memory for a receiveBuffer and I was trying to pass that buffer pointer as my buffer handle in the RIO_BUFFER_SEGMENT given to RioReceive instead of passing the IntPtr returned by RioRegisterBuffer.
I fully blame myself for using too many untyped IntPtrs and losing type checking. :)
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I've been using the site for a while and (after this semester) look forward to contributing back! However, I would like your help one last time and no other answers seem to have turned up any help.
BACKGROUND : Designing a basic chat room using c++, sockets, and a client/server architecture with up to ten clients talking to the server. Anything one client says is echoed among all clients and the server (with the exception of the sending client).
PROBLEM : The error occurs at the recv call as the while loop condition in the clientTalk function. I get a "Receive failed : Bad file descriptor" but neither the server nor the client "crash" completely and no noticeable change in behavior occurs, despite the fact that the receive bombed completely.
ATTEMPTS TO SOLVE:
Google and SOf. For 2 hours...
Moving variables, playing around with socket settings and opening/closing
-Valgrind:
==773== Warning: invalid file descriptor 96600128 in syscall read()
Recieve failed: Bad file descriptor
==773== Thread 2:
==773== Conditional jump or move depends on uninitialised value(s)
==773== at 0x4015A0: ??? (in /nethome/users/ghm455/CS284/ChatServer/server)
==773== by 0x4E39E99: start_thread (pthread_create.c:308)
==773== by 0x5442CBC: clone (clone.S:112)
==773==
==773== Conditional jump or move depends on uninitialised value(s)
==773== at 0x401614: ??? (in /nethome/users/ghm455/CS284/ChatServer/server)
==773== by 0x4E39E99: start_thread (pthread_create.c:308)
==773== by 0x5442CBC: clone (clone.S:112)
==773==
==773== Warning: invalid file descriptor 96600128 in syscall close()
The first warning occurs at my accept statement. The receive failed occurs at the recv and the last warning occurs on attempted close. This was determined by cout statements littered throughout the code.
CODE: Below. I'll post the client if you believe the error lies there, but everything points to this being a server side problem.
`#define SERVER_PORT 9999 /* define a server port number */
using std::cout;
using std::endl;
using std::string;
//Globals - descriptorArray holds client FDs. arraySize is its size.
//soc holds the information on the server's socket.
//m is the global mutex shared among the server and all clients
const int MAX_CLIENT = 10;
int descriptorArray[MAX_CLIENT];
int arraySize = 0;
int soc;
pthread_mutex_t m;
struct thread_info
{
pthread_t threadID; //Stores the ID number returned by pthread_create
int threadNumber; //We have to number incoming threads correctly
char *messageSent; //Message taken in from command line
};
int main()
{
void exitHandler(int sig); // Function that handles the control-C
void* clientTalk(void *arg); // Reads and writes with clients
struct sockaddr_in server_addr, client_addr;
int option = 1;
unsigned int clientCount;
uint8_t *new_socket;
//Initialize the socket
soc = socket(AF_INET, SOCK_STREAM, 0);
if (soc < 0)
{
cout << "ERROR : problem opening socket" <<endl;
return 1;
}
//Create socket structure
bzero((char *) &server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(SERVER_PORT);
//Binding host address
if (bind(soc, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0)
{
cout << "ERROR : problem occured while binding" <<endl;
close(soc);
exit(1);
}
if(setsockopt(soc, SOL_SOCKET, SO_REUSEADDR, (char*) &option, sizeof(option)) < 0)
{
printf("setsockopt failed\n");
close(soc);
exit(1);
}
signal(SIGINT, exitHandler);
listen(soc, MAX_CLIENT);
clientCount = sizeof(struct sockaddr_in);
int clientID;
//cout << "Z " <<endl;
while(clientID = accept(soc, (struct sockaddr *) &client_addr, (socklen_t*)&clientCount))
{
//printf( "A");
if (clientID < 0 )
{
perror("ERROR ON ACCEPT");
exit(1);
}
else
{
pthread_t newClient;
new_socket = (uint8_t*)malloc(1);
*new_socket = clientID;
pthread_mutex_lock(&m);
if (arraySize < 10)
{
descriptorArray[arraySize++] = newClient;
}
else
{
cout << "There are already 10 clients connected!" << endl;
}
pthread_mutex_unlock(&m);
if( pthread_create(&newClient, NULL, clientTalk, &new_socket) < 0)
{
perror("ERROR Creating thread");
return 1;
}
cout << "Assigned!" <<endl;
pthread_join(newClient, NULL);
}
}
close(soc);
return 0;
}
void exitHandler(int sig)
{
sig = sig + 0; //Removing the warning. A clean compile looks a lot nicer.
for (int i = 0; i < arraySize; i++)
{
write(descriptorArray[i], "WARNING: Server exiting in ten seconds. End your conversation!", 1000);
}
cout << "WARNING: Server exiting in ten seconds. ";
cout << "End your conversation!" << endl;
sleep(10f);
for (int i = 0; i < arraySize; i++)
{
close(descriptorArray[i]);
}
close(soc);
exit(1);
}
void* clientTalk(void* arg)
{
int* myFD = (int*) arg;
char buffer[2000];
read(*myFD, buffer, 20);
char username[20];
//strcpy(username, buffer); // Takes in the username and stores it
char movableString[2000];
int amount_read;
// for (int i = 0; i < arraySize; i++)
// {
//strcpy(movableString, username);
// strcat(movableString, " has joined the room!");
//if (descriptorArray[0] != *myFD)
//{
// write(descriptorArray[0], movableString, 2000);
//}
//}
cout << "x" << endl;
int arrayLocation;
while ( (amount_read = recv(*myFD, buffer, 2000, MSG_WAITALL)) > 0)
{
cout << " Um" << endl;
pthread_mutex_lock(&m);
for (int i = 0; i < arraySize; i++)
{
if (descriptorArray[i] == *myFD)
{
arrayLocation = i;
break;
}
}
strcpy(movableString, username);
strcat(movableString, ": ");
strcat(movableString, buffer);
for (int i = 0; i < arraySize; i++)
{
//if (i != arrayLocation)
//{
write(*myFD, movableString, 2000);
//}
}
pthread_mutex_unlock(&m);
}
if (amount_read == 0)
{
cout << username << "disconnected unexpectedly" <<endl;
fflush(stdout);
}
if (amount_read == -1)
{
perror("Recieve failed");
}
pthread_mutex_lock(&m);
for (int i = 0; i < arraySize; i++)
{
if (descriptorArray[i] == *myFD)
{
arrayLocation = i;
break;
}
}
for (int i = arrayLocation; i < arraySize - 1; i++)
{
descriptorArray[i] = descriptorArray[i + 1];
}
arraySize--;
pthread_mutex_unlock(&m);
close(*myFD);
pthread_exit(NULL);
free(arg);
}
`
I'll be monitoring this site to answer any questions you may have. I apologize in advance for making any novice mistakes in asking a question.
Thank you for your help!
The error means the file descriptor passed to the read function is not a valid file descriptor, so the first thing to do when debugging is to make sure the value of the file descriptor in the ClientTalk function is the same as in main.
#J.N. is right in the comments. They will not be the same because the FD is an int and you are only passing the first byte to the function (and converting it to an int* pointer.)
You might want to write this program in C as it doesn't look like C++ code.
Change ClientID and new_socket to int / int*.
Use consistent types, and use the types in the function definition accept returns an int so use int / int* for everything.
When calling malloc use sizeof not the number of bytes whenever possible.
There might be other problems.
There are at least two issues here. First, you never call pthread_mutex_init so your mutex was never created to a sane state (although it will be zeroed if it's at global scope).
Secondly, you pass &new_socket as the void* to your thread. This is of type uint8_t** while inside your clientTalk function you C-style-cast cast it to int* which is a totally different pointer type and will certainly not provide the result you desire.
I am trying to catch a SIGVTALRM sent by setitimer, and I have no idea why it doesn't work. here's my code:
void time(int time) {
cout << "time" << endl;
exit(0);
}
int main(void) {
signal(SIGVTALRM, time);
itimerval tv;
tv.it_value.tv_sec = 5;
tv.it_value.tv_usec = 0;
tv.it_interval.tv_sec = 5;
tv.it_interval.tv_usec = 0;
setitimer(ITIMER_VIRTUAL, &tv, NULL);
while (true) {
cout << "waiting" << endl;
}
return 0;
}
For some reason it never invokes time() - is it because it doesn't catch the signal or because the signal wasn't sent in the first place I don't know.
It should be pretty simple. Any ideas? thanks
Are you sure it is not working?
Everything looks fine to me. May be you are not waiting enough. Since you are printing the string waiting inside the loop and you are using the virtual timer, as a result the clock ticks only when the process runs (IO time not included). So in reality your timer might expire after several (>5) seconds.
Try commenting out the printing part.
It is due to signal function. As mentioned in http://manpages.ubuntu.com/manpages//precise/en/man2/signal.2.html:
The behavior of signal() varies across UNIX versions, and has also varied historically across different versions of Linux. Avoid its use: use sigaction(2) instead.
So the main method should be:
int main(void) {
itimerval tv;
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = timer_handler;
if (sigaction(SIGVTALRM, &sa, NULL) == -1) {
printf("error with: sigaction\n");
exit(EXIT_FAILURE);
}
tv.it_value.tv_sec = 5;
tv.it_value.tv_usec = 0;
tv.it_interval.tv_sec = 5;
tv.it_interval.tv_usec = 0;
setitimer(ITIMER_VIRTUAL, &tv, NULL);
while (true) {
cout << "waiting" << endl;
}
return 0;
}