CAsyncSocket in UI thread (Mr. Newcomer) - Programmer

This is a discussion on CAsyncSocket in UI thread (Mr. Newcomer) - Programmer ; Mr Newcomer. Previously, in a newsgroup post you had responded to another thread where I had asked about some operations with CAsyncSocket and you noted that I couldn't use CAsyncSocket in a worker thread- then you directed me to your ...

+ Reply to Thread
Results 1 to 2 of 2

Thread: CAsyncSocket in UI thread (Mr. Newcomer)

  1. CAsyncSocket in UI thread (Mr. Newcomer)

    Mr Newcomer.

    Previously, in a newsgroup post you had responded to another thread where I
    had asked about some operations with CAsyncSocket and you noted that I
    couldn't use CAsyncSocket in a worker thread- then you directed me to your
    web page to read your article about CAsyncSocket in UI threads. I wanted to
    send you a snippet of code (I've reduced it as much as possible to leave
    only the relevant stuff). Also, I apologize in advance for specifying you
    on the subject line. Previously, I had tried sending you an email from the
    link on your website but all my attempts were bounced back as 'not accepting
    email from spammers'. I tried under several email addresses (mine) both
    well known and super-secret, all got bounced as 'spam'. Oh well.

    Here is a section of server code which I have running in a worker thread
    started with AfxBeginThread([func],this);

    Also, forgive the sloppy coding, this is something I wrote as a prototype to
    understand functionality- plus email formatting has broken some of the
    neatness.

    Anyway, this code works and I currently have it running on my desktop now.
    I'm curious as to how this code works if one should not be able to get it
    working. My assumption at this point is to defer to your assertion that
    CAsyncSocket does not run properly in a worker thread, and I've got some
    process that is causing my code to unwittingly work.
    My structure is basically as thus: A single 'listener' thread starts,
    creating a listener socket which, after a successful connection is made (see
    the heavily commented block near end of Listener() member function)
    it detaches and launches a new thread in a 'talker thread'. As you may
    guess, there is a unique thread for each connection established, but only
    one thread which listens for and accepts connections. After the 'listener'
    function below, see the 'talker' function . Feel free to pester me for any
    further clarifications. Thank you in advance for any time and consideration
    you give to my email.

    bool CRedEyeDlg::Listener()
    {
    m_bThreadLoopRunning = true; //Indicate thread is started
    m_bListenerRunning = true; //Thread started, set control to true
    CAsyncSocket listener; //Server listener awaits new connections
    CAsyncSocket talker; //Socket for talking to client
    char* buffer = "Welcome to RedEye Server v1.0\r\n"; //Welcome message
    (will be variable later)

    m_strStatus = "Running...";

    /*Create the listener socket and set flags indicating
    if Create() fails.*/
    if(!listener.Create(m_nPort,SOCK_STREAM,NULL)){
    m_bThreadLoopRunning = false;
    m_bListenerRunning = false;
    EnableControls(); //Must move out of thread later
    return false;
    }

    EnableControls(); //Set buttons on dialog must move

    //Set up listener to 'listen'. If the setup fails, set flags
    // indicating that the setup failed, end thread etc.

    if(!listener.Listen(5)){
    m_bThreadLoopRunning = false;
    m_bListenerRunning = false;
    EnableControls(); //Must move out of thread
    return false;
    }

    //While the flag remains true, attempt to accept any new
    // connections into listener socket on socket 'talker'.
    // If a connection is made, detach talker socket, start
    // a new thread for the communication between the connected
    // sockets, then go back to trying to accept new connections.
    //A code review is likely needed here just in case the new
    // talker thread doesn't 'attach' successfully to the new socket
    // before another accept attempt is made (in this thread).
    ::PostMessage(m_hWnd,MY_WM_UPDATESTATUS,0,0);

    //handle some sql stuff here

    while(m_bListenerRunning){
    if(listener.Accept(talker,NULL,NULL)){
    talker.Send((void*)buffer,strlen(buffer),0); //Send welcome
    message
    m_hSocket = talker.Detach();
    AfxBeginThread(StartTalker,this);
    }
    ::Sleep(50);
    }

    m_strStatus = "Stopped...";
    m_strLastAction = "Waiting for threads to close...";
    ::PostMessage(m_hWnd,MY_WM_UPDATESTATUS,0,0);

    m_bThreadLoopRunning = false;

    while(m_nTalkerThreadCount){
    ::Sleep(50);
    }

    m_strLastAction = "None...";
    ::PostMessage(m_hWnd,MY_WM_UPDATESTATUS,0,0);

    return true;
    }

    Here is the 'talker' thread- this uses an inherited class from CAsyncSocket
    which I call 'ccommo'. I won't include the source here because it doesn't
    do much beyond CAsyncSocket, except I've created some new functions which
    allow me to 'look for' data on the line which maches a certain response with
    a timeout. There are some other functions which are non-commo related so I
    won't detail them. Most of this code was useful in teaching myself dealing
    with 'lost' connections. I've never done much more with it since then,
    however.

    bool CRedEyeDlg::Talker()
    {
    //This runs within a thread of its own. Its primary responsibility
    // is to run communications between the server (this program) and the
    // client. It updates the talker thread count variable which alerts
    // the server as to how many of these threads are currently running.
    // For now, this thread monitors the main thread control flag. If that

    // flag goes false, any talker threads will quit (bListenerRunning).
    //Each thread has a variable 'bSocketGood'. As long as that remains
    true,
    // the individual thread will stay open. The main loop in this
    function
    // reads both bListenerRunning and bSocketGood. bSocketGood is set to
    false
    // if critical failures occur within this thread, which will
    subsequently kill
    // just this thread. Other talker threads will continue.

    m_nTalkerThreadCount++; //Incremenent thread count
    CCommo talker; //Socket for communication to client
    int nResult = 0;
    int nLastError = 0;
    int nBufferlen = 0;
    CString response;
    CString work;
    CString User;
    CString ip;
    bool bSocketGood = true; //Indicate socket is good. false == socket
    failed
    int hack = 0; //time hack for testing socket timeout
    MESSAGEDATA ClientMessage; //Message data block
    CMessage* rs = NULL; //Record set which represents messages waiting

    //Initialize members
    ClientMessage.nMessageType = 0;
    ClientMessage.bAuthenticated = false; //Flag indicating user has been
    authenticated

    if(!talker.Attach(m_hSocket)){
    m_nTalkerThreadCount--;
    return false;
    }

    talker.GetUserInfo(User,ip);

    work = "Hello " + ip + "\r\n\r\n";
    nBufferlen = work.GetLength();
    talker.Send((void*)work.GetBuffer(0),nBufferlen,0) ;
    work.ReleaseBuffer();

    //Update status indicating thread has started
    ::PostMessage(m_hWnd,MY_WM_UPDATESTATUS,0,0);

    hack = time(NULL);
    //Main talk loop.
    while(m_bListenerRunning && bSocketGood){
    nResult = talker.Peek();
    nLastError = talker.GetLastError();

    if(!nResult) //No data received?
    break;

    switch(nLastError){
    case WSAENETDOWN:
    {
    bSocketGood = false;
    break;
    }
    case WSAENOTCONN:
    {
    bSocketGood = false;
    break;
    }
    case WSAESHUTDOWN:
    {
    bSocketGood = false;
    break;
    }
    case WSAECONNABORTED:
    {
    bSocketGood = false;
    break;
    }
    case WSAECONNRESET:
    {
    bSocketGood = false;
    break;
    }
    case WSAEWOULDBLOCK:
    {
    //This will change so some kind of query back and forth could take
    place
    // to verify the connection. But for now, if NO DATA of any kind
    has been
    // received from the client in the SOCKET_TIMEOUT period, the socket
    gets
    // closed. Too bad, so sad.
    if(time(NULL) - hack > SOCKET_TIMEOUT)
    bSocketGood = false; // if it's not, indicate socket
    has failed and get out of loop
    break;
    }
    default:
    break;
    }

    if(nResult > 0){
    hack = time(NULL); //Got some data, reset the time hack
    nResult = talker.GetResponse(response);
    //test code to see responses

    //Mr. Newcomer--> below is code which I don't believe to be relevant in
    that
    // it's designed to 'deal' with responses from the client. Most of this
    is fluff and secondary
    // to the main communications.
    if(!Tasker(response,&talker,&ClientMessage)) //Tasker had some
    fatal error
    bSocketGood = false; //Shut down thread
    //end Test code to see responses
    }else{ //No data from client, see if there are messages waiting.

    rs = CheckForMessages(&ClientMessage);
    if(rs){ //There were messages waiting
    response = "" + ClientMessage.strMessageBlock + "\r\n";
    nBufferlen = response.GetLength();
    talker.Send((void*)response.GetBuffer(0),nBufferle n,0);
    response.ReleaseBuffer();
    talker.GetResponse(response);
    if(response != "\r\n")
    bSocketGood = false;
    else
    rs->Delete();
    delete rs;
    rs = NULL;
    }
    }
    ::Sleep(50);
    }

    ::PostMessage(m_hWnd,MY_WM_UPDATESTATUS,0,0);
    m_nTalkerThreadCount--; //Thread terminating, decrement counter
    return true;
    }





  2. Re: CAsyncSocket in UI thread (Mr. Newcomer)

    I found that it worked if I used the MCF library in the dll's but it doesn't
    work if I statically link.
    Mike

    "Pablo" wrote in message
    news:vt22s257iuqo64@corp.supernews.com...
    > Mr Newcomer.
    >
    > Previously, in a newsgroup post you had responded to another thread where

    I
    > had asked about some operations with CAsyncSocket and you noted that I
    > couldn't use CAsyncSocket in a worker thread- then you directed me to your
    > web page to read your article about CAsyncSocket in UI threads. I wanted

    to
    > send you a snippet of code (I've reduced it as much as possible to leave
    > only the relevant stuff). Also, I apologize in advance for specifying you
    > on the subject line. Previously, I had tried sending you an email from

    the
    > link on your website but all my attempts were bounced back as 'not

    accepting
    > email from spammers'. I tried under several email addresses (mine) both
    > well known and super-secret, all got bounced as 'spam'. Oh well.
    >
    > Here is a section of server code which I have running in a worker thread
    > started with AfxBeginThread([func],this);
    >
    > Also, forgive the sloppy coding, this is something I wrote as a prototype

    to
    > understand functionality- plus email formatting has broken some of the
    > neatness.
    >
    > Anyway, this code works and I currently have it running on my desktop now.
    > I'm curious as to how this code works if one should not be able to get it
    > working. My assumption at this point is to defer to your assertion that
    > CAsyncSocket does not run properly in a worker thread, and I've got some
    > process that is causing my code to unwittingly work.
    > My structure is basically as thus: A single 'listener' thread starts,
    > creating a listener socket which, after a successful connection is made

    (see
    > the heavily commented block near end of Listener() member function)
    > it detaches and launches a new thread in a 'talker thread'. As you may
    > guess, there is a unique thread for each connection established, but only
    > one thread which listens for and accepts connections. After the

    'listener'
    > function below, see the 'talker' function . Feel free to pester me for

    any
    > further clarifications. Thank you in advance for any time and

    consideration
    > you give to my email.
    >
    > bool CRedEyeDlg::Listener()
    > {
    > m_bThreadLoopRunning = true; //Indicate thread is started
    > m_bListenerRunning = true; //Thread started, set control to true
    > CAsyncSocket listener; //Server listener awaits new connections
    > CAsyncSocket talker; //Socket for talking to client
    > char* buffer = "Welcome to RedEye Server v1.0\r\n"; //Welcome message
    > (will be variable later)
    >
    > m_strStatus = "Running...";
    >
    > /*Create the listener socket and set flags indicating
    > if Create() fails.*/
    > if(!listener.Create(m_nPort,SOCK_STREAM,NULL)){
    > m_bThreadLoopRunning = false;
    > m_bListenerRunning = false;
    > EnableControls(); //Must move out of thread later
    > return false;
    > }
    >
    > EnableControls(); //Set buttons on dialog must move
    >
    > //Set up listener to 'listen'. If the setup fails, set flags
    > // indicating that the setup failed, end thread etc.
    >
    > if(!listener.Listen(5)){
    > m_bThreadLoopRunning = false;
    > m_bListenerRunning = false;
    > EnableControls(); //Must move out of thread
    > return false;
    > }
    >
    > //While the flag remains true, attempt to accept any new
    > // connections into listener socket on socket 'talker'.
    > // If a connection is made, detach talker socket, start
    > // a new thread for the communication between the connected
    > // sockets, then go back to trying to accept new connections.
    > //A code review is likely needed here just in case the new
    > // talker thread doesn't 'attach' successfully to the new socket
    > // before another accept attempt is made (in this thread).
    > ::PostMessage(m_hWnd,MY_WM_UPDATESTATUS,0,0);
    >
    > //handle some sql stuff here
    >
    > while(m_bListenerRunning){
    > if(listener.Accept(talker,NULL,NULL)){
    > talker.Send((void*)buffer,strlen(buffer),0); //Send welcome
    > message
    > m_hSocket = talker.Detach();
    > AfxBeginThread(StartTalker,this);
    > }
    > ::Sleep(50);
    > }
    >
    > m_strStatus = "Stopped...";
    > m_strLastAction = "Waiting for threads to close...";
    > ::PostMessage(m_hWnd,MY_WM_UPDATESTATUS,0,0);
    >
    > m_bThreadLoopRunning = false;
    >
    > while(m_nTalkerThreadCount){
    > ::Sleep(50);
    > }
    >
    > m_strLastAction = "None...";
    > ::PostMessage(m_hWnd,MY_WM_UPDATESTATUS,0,0);
    >
    > return true;
    > }
    >
    > Here is the 'talker' thread- this uses an inherited class from

    CAsyncSocket
    > which I call 'ccommo'. I won't include the source here because it doesn't
    > do much beyond CAsyncSocket, except I've created some new functions which
    > allow me to 'look for' data on the line which maches a certain response

    with
    > a timeout. There are some other functions which are non-commo related so

    I
    > won't detail them. Most of this code was useful in teaching myself

    dealing
    > with 'lost' connections. I've never done much more with it since then,
    > however.
    >
    > bool CRedEyeDlg::Talker()
    > {
    > //This runs within a thread of its own. Its primary responsibility
    > // is to run communications between the server (this program) and the
    > // client. It updates the talker thread count variable which alerts
    > // the server as to how many of these threads are currently running.
    > // For now, this thread monitors the main thread control flag. If that
    >
    > // flag goes false, any talker threads will quit (bListenerRunning).
    > //Each thread has a variable 'bSocketGood'. As long as that remains
    > true,
    > // the individual thread will stay open. The main loop in this
    > function
    > // reads both bListenerRunning and bSocketGood. bSocketGood is set to
    > false
    > // if critical failures occur within this thread, which will
    > subsequently kill
    > // just this thread. Other talker threads will continue.
    >
    > m_nTalkerThreadCount++; //Incremenent thread count
    > CCommo talker; //Socket for communication to client
    > int nResult = 0;
    > int nLastError = 0;
    > int nBufferlen = 0;
    > CString response;
    > CString work;
    > CString User;
    > CString ip;
    > bool bSocketGood = true; //Indicate socket is good. false == socket
    > failed
    > int hack = 0; //time hack for testing socket timeout
    > MESSAGEDATA ClientMessage; //Message data block
    > CMessage* rs = NULL; //Record set which represents messages waiting
    >
    > //Initialize members
    > ClientMessage.nMessageType = 0;
    > ClientMessage.bAuthenticated = false; //Flag indicating user has been
    > authenticated
    >
    > if(!talker.Attach(m_hSocket)){
    > m_nTalkerThreadCount--;
    > return false;
    > }
    >
    > talker.GetUserInfo(User,ip);
    >
    > work = "Hello " + ip + "\r\n\r\n";
    > nBufferlen = work.GetLength();
    > talker.Send((void*)work.GetBuffer(0),nBufferlen,0) ;
    > work.ReleaseBuffer();
    >
    > //Update status indicating thread has started
    > ::PostMessage(m_hWnd,MY_WM_UPDATESTATUS,0,0);
    >
    > hack = time(NULL);
    > //Main talk loop.
    > while(m_bListenerRunning && bSocketGood){
    > nResult = talker.Peek();
    > nLastError = talker.GetLastError();
    >
    > if(!nResult) //No data received?
    > break;
    >
    > switch(nLastError){
    > case WSAENETDOWN:
    > {
    > bSocketGood = false;
    > break;
    > }
    > case WSAENOTCONN:
    > {
    > bSocketGood = false;
    > break;
    > }
    > case WSAESHUTDOWN:
    > {
    > bSocketGood = false;
    > break;
    > }
    > case WSAECONNABORTED:
    > {
    > bSocketGood = false;
    > break;
    > }
    > case WSAECONNRESET:
    > {
    > bSocketGood = false;
    > break;
    > }
    > case WSAEWOULDBLOCK:
    > {
    > //This will change so some kind of query back and forth could take
    > place
    > // to verify the connection. But for now, if NO DATA of any kind
    > has been
    > // received from the client in the SOCKET_TIMEOUT period, the socket
    > gets
    > // closed. Too bad, so sad.
    > if(time(NULL) - hack > SOCKET_TIMEOUT)
    > bSocketGood = false; // if it's not, indicate socket
    > has failed and get out of loop
    > break;
    > }
    > default:
    > break;
    > }
    >
    > if(nResult > 0){
    > hack = time(NULL); //Got some data, reset the time hack
    > nResult = talker.GetResponse(response);
    > //test code to see responses
    >
    > //Mr. Newcomer--> below is code which I don't believe to be relevant in
    > that
    > // it's designed to 'deal' with responses from the client. Most of this
    > is fluff and secondary
    > // to the main communications.
    > if(!Tasker(response,&talker,&ClientMessage)) //Tasker had some
    > fatal error
    > bSocketGood = false; //Shut down thread
    > //end Test code to see responses
    > }else{ //No data from client, see if there are messages waiting.
    >
    > rs = CheckForMessages(&ClientMessage);
    > if(rs){ //There were messages waiting
    > response = "" + ClientMessage.strMessageBlock + "\r\n";
    > nBufferlen = response.GetLength();
    > talker.Send((void*)response.GetBuffer(0),nBufferle n,0);
    > response.ReleaseBuffer();
    > talker.GetResponse(response);
    > if(response != "\r\n")
    > bSocketGood = false;
    > else
    > rs->Delete();
    > delete rs;
    > rs = NULL;
    > }
    > }
    > ::Sleep(50);
    > }
    >
    > ::PostMessage(m_hWnd,MY_WM_UPDATESTATUS,0,0);
    > m_nTalkerThreadCount--; //Thread terminating, decrement counter
    > return true;
    > }
    >
    >
    >
    >




+ Reply to Thread