Example program with HTTPServer and sensor data streaming over TCPSockets, using Donatien Garnier's Net APIs and services code on top of LWIP. Files StreamServer.h and .cpp encapsulate streaming over TCPSockets. Broadcast is done by sendToAll(), and all incoming data is echoed back to the client. Echo code can be replaced with some remote control of the streaming interface. See main() that shows how to periodically send some data to all subscribed clients. To subscribe, a client should open a socket at <mbed_ip> port 123. I used few lines in TCL code to set up a quick sink for the data. HTTP files are served on port 80 concurrently to the streaming.
StreamServer.cpp
00001 00002 /* 00003 Copyright (c) 2010 IVA2K 00004 00005 Permission is hereby granted, free of charge, to any person obtaining a copy 00006 of this software and associated documentation files (the "Software"), to deal 00007 in the Software without restriction, including without limitation the rights 00008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00009 copies of the Software, and to permit persons to whom the Software is 00010 furnished to do so, subject to the following conditions: 00011 00012 The above copyright notice and this permission notice shall be included in 00013 all copies or substantial portions of the Software. 00014 00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00020 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00021 THE SOFTWARE. 00022 */ 00023 00024 #include "StreamServer.h" 00025 00026 #include "dbg/dbg.h" 00027 00028 00029 //BEGIN REQUEST DISPATCHER====================================================== 00030 StreamRequestDispatcher::StreamRequestDispatcher(StreamServer* pSvr, TCPSocket* pTcpSocket) 00031 : NetService(), m_pSvr(pSvr), m_pTcpSocket(pTcpSocket), m_closed(false) 00032 { 00033 m_pTcpSocket->setOnEvent(this, &StreamRequestDispatcher::onTcpSocketEvent); 00034 } 00035 00036 StreamRequestDispatcher::~StreamRequestDispatcher() 00037 { 00038 //DBG("deleting\r\n"); 00039 close(); 00040 } 00041 00042 int StreamRequestDispatcher::writeData(const char* buf, int len) 00043 { 00044 if(m_closed) { 00045 //DBG("m_closed\r\n"); 00046 return TCPSOCKET_RST; 00047 } 00048 int ret = m_pTcpSocket->send(buf, len); 00049 if (ret != len) DBG("ret=%d\r\n", ret); 00050 return ret; 00051 } 00052 00053 //FIXME: Need implementation for StreamServer 00054 void StreamRequestDispatcher::dispatchRequest() 00055 { 00056 string request; 00057 const char* buf; 00058 int len, ret; 00059 // DBG("\r\n"); 00060 00061 //FIXME: here is the place to implement custom request handler 00062 00063 while ( getRequest(&request) ) 00064 { 00065 // Just echo it back 00066 buf = request.c_str(); 00067 len = strlen(buf); 00068 ret = writeData(buf,len); 00069 writeData("\r\n",2); 00070 DBG("Received req (%s), write ret=%d\r\n", buf, ret); 00071 } 00072 } 00073 00074 void StreamRequestDispatcher::close() //Close socket and destroy data 00075 { 00076 if(m_closed) { 00077 //DBG("already closed\r\n"); 00078 return; 00079 } 00080 m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else 00081 //DBG("removing from list\r\n"); 00082 m_pSvr->m_lpClients.remove(this); 00083 if(m_pTcpSocket) 00084 { 00085 //DBG("closing socket\r\n"); 00086 m_pTcpSocket->resetOnEvent(); 00087 m_pTcpSocket->close(); // FIXME: in bad cause of events, getting "could not close properly, abort" log message 00088 delete m_pTcpSocket; 00089 } 00090 //DBG("closing service\r\n"); 00091 NetService::close(); 00092 } 00093 00094 bool StreamRequestDispatcher::getRequest(string* request) 00095 { 00096 const int maxLen = 64; 00097 char req[maxLen]; 00098 //Read Line 00099 int ret; 00100 int len = 0; 00101 char* p = req; 00102 for(int i = 0; i < maxLen - 1; i++) 00103 { 00104 ret = m_pTcpSocket->recv(p, 1); 00105 //FIXME: handle errors here (ret < 0)? 00106 if(!ret) 00107 { 00108 break; 00109 } 00110 #if 1 00111 // Consider incoming symbols - line ends etc. 00112 if( (len > 1) && *(p-1)=='\r' && *p=='\n' ) 00113 { 00114 p--; 00115 len-=2; 00116 break; 00117 } 00118 else if( *p=='\n' ) 00119 { 00120 len--; 00121 break; 00122 } 00123 #endif 00124 p++; 00125 len++; 00126 } 00127 *p = 0; 00128 00129 DBG("Parsing request (%s) ret=%d\r\n", req, ret); 00130 00131 *request = string(req); 00132 00133 return (len > 0); 00134 } 00135 00136 00137 void StreamRequestDispatcher::onTcpSocketEvent(TCPSocketEvent e) 00138 { 00139 DBG("Event %d\r\n", e); 00140 00141 if(m_closed) 00142 { 00143 DBG("WARN: Discarded\r\n"); 00144 return; 00145 } 00146 00147 switch(e) 00148 { 00149 case TCPSOCKET_READABLE: 00150 //Req arrived, dispatch : 00151 dispatchRequest(); 00152 break; 00153 case TCPSOCKET_CONTIMEOUT: 00154 case TCPSOCKET_CONRST: 00155 case TCPSOCKET_CONABRT: 00156 case TCPSOCKET_ERROR: 00157 case TCPSOCKET_DISCONNECTED: 00158 close(); 00159 break; 00160 } 00161 00162 } 00163 //END REQUEST DISPATCHER======================================================== 00164 00165 00166 StreamServer::StreamServer() 00167 { 00168 m_pTcpSocket = new TCPSocket; 00169 m_pTcpSocket->setOnEvent(this, &StreamServer::onTcpSocketEvent); 00170 } 00171 00172 StreamServer::~StreamServer() 00173 { 00174 delete m_pTcpSocket; 00175 } 00176 00177 void StreamServer::bind(int port /*= 123*/) 00178 { 00179 Host h(IpAddr(127,0,0,1), port, "localhost"); 00180 m_pTcpSocket->bind(h); 00181 m_pTcpSocket->listen(); //Listen 00182 } 00183 00184 #if 0 //Just for clarity 00185 template<typename T> 00186 void StreamServer::addHandler(const char* path) 00187 { 00188 // m_lpHandlers[path] = &T::inst; 00189 } 00190 #endif 00191 00192 void StreamServer::sendToAll(const char* buf, int len) 00193 { 00194 int ret; 00195 int i = 0; 00196 tClients::iterator it; 00197 for(it = m_lpClients.begin(); it != m_lpClients.end(); /* No increment here */ ) 00198 { 00199 ret = (*it)->writeData(buf, len); 00200 if ( 00201 ret == TCPSOCKET_RST // This is a safety valve. We should have self-removed from m_lpClients upon socket closure and not get here. 00202 || ret == TCPSOCKET_MEM // This probably means that network is not delivering packets, and we're backed up. 00203 ) { 00204 DBG("(%s) Socket error 0x%04X - erasing socket %d\r\n", buf, ret, i); 00205 // delete below will remove (*it) from the list we are iterating in. Prepare for that 00206 tClients::iterator it_next = it; 00207 it_next++; 00208 delete (*it); 00209 it = it_next; 00210 continue; // This ensures that for(...) above will continue properly. 00211 } 00212 i++; 00213 it++; /* increment the iterator */ 00214 } 00215 } 00216 00217 int StreamServer::countClients(void) 00218 { 00219 return m_lpClients.size(); 00220 } 00221 00222 void StreamServer::onTcpSocketEvent(TCPSocketEvent e) 00223 { 00224 00225 DBG("Event %d\r\n", e); 00226 00227 if(e==TCPSOCKET_ACCEPT) 00228 { 00229 TCPSocket* pTcpSocket; 00230 Host client; 00231 00232 if( !!m_pTcpSocket->accept(&client, &pTcpSocket) ) 00233 { 00234 DBG("Could not accept connection.\r\n"); 00235 return; //Error in accept, discard connection 00236 } 00237 00238 StreamRequestDispatcher* pDispatcher = new StreamRequestDispatcher(this, pTcpSocket); //TcpSocket ownership is passed to dispatcher 00239 //The dispatcher object will destroy itself when its socket closes, or will be destroyed on Server destruction 00240 m_lpClients.push_back(pDispatcher); 00241 } 00242 } 00243 00244 //END
Generated on Tue Jul 12 2022 21:10:26 by 1.7.2