///////////////////////////////////////////////////////////////////////// // comm.cpp - communication classes, used by client and server // // ver 1.1 to setup and use message-passing communications // // // // Language: Visual C++, ver 6.0 // // Platform: Dell Dimension 8100, Windows 2000 Pro, SP1 // // Application: CSE691/791 help // // Author: Jim Fawcett, CST 2-187, Syracuse University // // (315) 443-3948, jfawcett@twcny.rr.com // ///////////////////////////////////////////////////////////////////////// #include #include #include "comm.h" #include "lockingPtr.h" #include "thrdsWithProc.h" using namespace std; //----< client constructor >--------------------------------------------- commClt::commClt() : _sendProc(_client), _recvProc(_client), _sender(_sendProc), _recver(_recvProc) { _sender.setPriority(thread::low); _recver.setPriority(thread::high); _pRecvQ = _recvProc.precvQ(); } //----< client destructor >---------------------------------------------- commClt::~commClt() { safeOut sout(cout); sout << "\n waiting on sender in commClt destructor"; _sender.wait(); sout << "\n waiting on recver in commClt destructor"; _recver.wait(); sout << "\n finished waiting, bye\n\n"; } // //----< connect to server >---------------------------------------------- bool commClt::connect(const char *server, int port) { return connect(std::string(server),port); } //----< conect to server >----------------------------------------------- bool commClt::connect(std::string &server, int port) { bool connected = _client.connectTo(server,port); if(connected) { _sender.start(); _recver.start(); } return connected; } //----< enQueue a message for server >----------------------------------- void commClt::postMessage(message &msg) { cltSendQlocker lock; cltSendQlp(_sendProc.sendQ(),lock)->enQ(msg); } //----< deQueue a message from server >---------------------------------- // // If there is a message, it will be stored in msg, message referred to, // and true returned. Otherwise msg is unchanged and false is returned. // bool commClt::getMessage(message &msg) { cltRecvQlocker lock; int len = cltRecvQlp(*_pRecvQ,lock)->length(); if(len > 0) { msg = cltRecvQlp(*_pRecvQ,lock)->deQ(); return true; } return false; } // //----< server constructor >--------------------------------------------- commSvr::commSvr(int port) : _server(port), _serverProc(), _serverThread(_serverProc) { _serverThread.start(); } //----< server destructor >---------------------------------------------- commSvr::~commSvr() { } //----< deQueue a message from client >---------------------------------- bool commSvr::getMessage(int &clientID, message &msg) { message temp; cmlocker cmLock; mtqueue &recvQ = connMgrlp(_connMgr,cmLock)->recvQ(); svrRecvQlocker rQlock; int len = svrRecvQlp(recvQ,rQlock)->length(); if(len > 0) { temp = svrRecvQlp(recvQ,rQlock)->deQ(); clientID = StrToT(temp.body()).convert(); msg = svrRecvQlp(recvQ,rQlock)->deQ(); return true; } return false; } //----< enQueue message for client >------------------------------------- void commSvr::postMessage(int clientID, const message &msg) { cmlocker cmLock; mtqueue &sendQ = connMgrlp(_connMgr,cmLock)->sendQ(clientID); svrSendQlocker sQlock; svrSendQlp(sendQ,sQlock)->enQ(msg); } // #ifdef TEST_COMM_SERVER //----< commSvr test stub >---------------------------------------------- // // The following test stub illustrates how easy it is to use the // commSvr class. Clients of this class do not have to do multi- // threaded programming to use this responsive multi-threaded // socket-based communication system. // // The only responsibilities commSvr users have are to: // // (1) always return the clientID, extracted from a message, // with the response to that message. That gets the // message routed to the right client. You have to do // this even if there is only one active client. // (2) always send back any quit message found in the // server receive stream by posting back the quit message // along with its clientID. That ensures that the server // flushes its socket stream so that the client will get // all the data you sent and can gracefully shut down. // // You will note that commSvr users have to poll the commSvr's // receive queue. Notifications where not implemented to keep // things as simple as possible. That is planned for a later // version. // void main() { safeOut sout(cout); sout << locker << "\n Demonstrate Communication Server Class " << "\n ========================================\n" << unlocker; commSvr server(1024); message recvMsg; int clientID; do { if(!server.getMessage(clientID,recvMsg)) // nothing in the receive queue so sleep for awhile ::Sleep(50); else { // received message from client, so display it // and then send it back to the client sout << locker << "\n received: " << recvMsg.serialize() << unlocker; // Post back all messages, including the final quit. // This is not a very exciting server activity, but // it illustrates rich two-way communication between // client and server. server.postMessage(clientID,recvMsg); } } while(1); } #endif // #ifdef TEST_COMM_CLIENT //----< commClt test stub >---------------------------------------------- void main() { safeOut sout(cout); sout << locker << "\n Demonstrate Communication Client Class " << "\n ========================================\n" << unlocker; commClt client; if(!client.connect("127.0.0.1",1024)) sout << "\n could not connect to server"; else sout << "\n connected to server"; message sendMsg1(message::text,"this is test1"); /* client.postMessage(sendMsg1); message sendMsg2(message::text,"this is test2"); client.postMessage(sendMsg2); message sendMsg3(message::text,"this is test3"); client.postMessage(sendMsg3); message sendMsg4(message::text,"this is test4"); client.postMessage(sendMsg4); message sendMsg5(message::text,"this is test5"); client.postMessage(sendMsg5); message sendMsg6(message::text,"this is test6"); client.postMessage(sendMsg6); message quitMsg(message::text,"quit"); client.postMessage(quitMsg); */ message recvMsg; do { client.postMessage(sendMsg1); if(!client.getMessage(recvMsg)) ::Sleep(50); else { sout << locker << "\n received: " << recvMsg.serialize() << unlocker; } } while(recvMsg.body() != "quit"); } #endif