⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 samplesocketport.cpp

📁 贡献一份commoncpp2,有兴趣的可以研究一下
💻 CPP
字号:
/** * *	This class demonstrates use of the CommonC++ SocketPort class. * *	Copyright 2001 - Nick Liebmann <nick@ukmail.org> *	 *	The SampleSocketPort is an implementation of the CommonC++ SocketPort class *	that irons out some problems that I found with disconnection, and also demonstrates *	a way of using the SocketPort to reliably extract and send data from/to a TCP/IP socket. *	 *	In addition to this the SampleSocketPort includes some additional functionality *	to determine whether the data stream has become corrupted *	(missing terminator / incorrect formatting). For this feature a timer is used which if it is *	allowed to expire, indicates that a 'packet' took too long to arrive, and as such the data  *	in the buffer is 'corrupt'. *	 *	The SampleSocketPort can be used as-is...Modify the contents of the pending() *	function if your data is formatted differently to the default (i.e. not terminated with \r\n) *	 *	 *	This sample code is distributed under the same terms and conditions of the CommonC++ library. *	 *	CHANGE HISTORY: *	 *	 *	07/01/02	NL		There have been slight changes to the way CommonC++ starts threads, *						a possible bug in InetHostAddress constructor, and a bug fix for SocketService *						#496276. The following changes address those issues *						 *						New thread start semantics. SocketService Thread is now explicitly started  *						by the SampleSocketServiceServer. *						 *						Added SampleSocketServiceServer::StartServer() to start the server and wait  *						for the thread to get up and running. *						 *						Added SampleSocketServiceServer::StopServer() to cleanly stop the server, and *						ensure that there are no partially constructed SocketPorts left lying around *						 *						Removed setDetectOutput(true)...this does not seem to be required anymore *						as the SocketService functions correctly now. *						 *						InetHostAddress constructor does not treat INADDR_ANY as it used to. *						 *	07/01/02	NL		main() - now waits for a 'quit' command, and deletes the Server object. */#include "SampleSocketPort.h"SampleSocketPort::SampleSocketPort(SocketService *pService, TCPSocket & tcpSocket) : 				SocketPort(pService, tcpSocket){	tpport_t port;	InetHostAddress ia = getPeer( & port );	cerr << "connecting from " << ia.getHostname() << ":" << port << endl;	// Set up non-blocking reads	setCompletion( false );	//1.9.3 THIS LINE DOES NOT SEEM TO BE REQUIRED ANYMORE!	//This sorts out a bug which prevents connections after a disconnect	//setDetectOutput(true);	m_bOpen = true;	m_bDoDisconnect = false;	m_bTimedOut = false;	m_bReceptionStarted = false;	m_nLastBytesAvail = 0;	m_pBuf = new char[MAX_RXBUF];}SampleSocketPort::~SampleSocketPort(){	endSocket();	delete [] m_pBuf;}void SampleSocketPort::pending(void){//cerr << "Pending called " << endl;	if(!m_bOpen)		return;	// Read all available bytes into our buffer	int nBytesAvail = peek(m_pBuf, MAX_RXBUF);//cerr << "Pending .. " << nBytesAvail << endl;	if(!m_bReceptionStarted)	{	//Start the receive timer		ResetReadTimeout(MAX_RXTIMEOUT);	//Got 'n' seconds to get all the data else we timeout		m_bReceptionStarted = true;	}	else	{		if(m_bTimedOut)	//The receive timer has expired...this is a timeout condition		{			ResetReadTimeout(MAX_RXTIMEOUT); //Clear the timeout flag			m_nLastBytesAvail = 0;		//Reset the flags			m_bReceptionStarted = false;			OnRxTimeout();	//Do whatever 'we' do for a timeout (probably a flush or disconnect)...			return;		}	}	if(m_nLastBytesAvail == nBytesAvail)	//Check if any more data has been received since last time	{										//No point in parsing unless this has changed!		//Maybe yield in here!		//Thread::yield();		if(nBytesAvail == 0)		//If we have been called with 0 bytes available (twice now)		{							//a disconnection has occurred			if(!m_bDoDisconnect)			{				CloseSocket();	//Force the close			}		}		return;	}	//Depending on your application you may want to attempt to process the extra data 	//(or change your MAX_RXBUF).	//	//Here I just flush the whole lot, because I assume a 'legal' client wont send more than	//we can receive....maybe someone is trying to flood / overrun us!	if(nBytesAvail > MAX_RXBUF)		{		cerr << "TCP/IP overflow..." << endl;		FlushRxData();		m_nLastBytesAvail = 0;		m_bReceptionStarted = false;		return;	}	m_nLastBytesAvail = nBytesAvail;	//In this loop you may parse the received data to determine whether a whole	//'packet' has arrived. What you do in here depends on what data you are sending.	//Here we will just look for a /r/n terminator sequence.	for(int i=0; i < nBytesAvail; i++)	{/***************************SHOULD BE CUSTOMISED*******************/		if(m_pBuf[i] == '\r')		{			if(i+1 < nBytesAvail)			{				if(m_pBuf[i+1] == '\n')				{	//Terminator sequence found					/**************************************************************/					// COMPULSORY ... Clear the flag and count..					// do this when you have received a good packet					m_nLastBytesAvail = 0;					m_bReceptionStarted = false;					/**************************************************************/					// Now receive the data into a buffer and call our receive function					int nLen = i+2;					char *pszRxData = new char[nLen+1];	//Allow space for terminator					receive(pszRxData, nLen);		//Receive the data					pszRxData[nLen] = '\0';		//Terminate it					OnDataReceived(pszRxData, nLen);					delete [] pszRxData;					return;				}			}		}/***************************END CUSTOMISATION*******************/	}}void SampleSocketPort::disconnect(void){	if(m_bOpen)	{		m_bDoDisconnect = true;		CloseSocket();	}}void SampleSocketPort::expired(void){	if(m_bDoDisconnect && m_bOpen)	{		CloseSocket();	}	else if(m_bOpen && m_bReceptionStarted)	{		//Timer must have expired because the rx data has not all been received		m_bTimedOut = true;	}}bool SampleSocketPort::CloseSocket(void){	if(m_bOpen && m_bDoDisconnect)	{									//This is where the disconnection really occurs		m_bOpen = false;				//If m_bDoDisconnect == true we know this has been called 		OnConnectionClosed();			//through the timer, so 'delete this' is safe!		delete this;	}	else if(m_bOpen)	{		m_bDoDisconnect = true;			//Just set the timer and the flag so we can 		setTimer(DISCONNECT_MS);		//disconnect safely, in DISCONNECT_MS	}	return(true);}ssize_t SampleSocketPort::DoSend(void *buf, size_t len){	//If we are disconnecting, just pretend all the bytes were sent	if(m_bDoDisconnect)		return((ssize_t)len);	ssize_t nSent = send(buf, len);	while(!isPending(Socket::pendingOutput, 0))		//Wait for output to complete	{		if(m_bDoDisconnect || !m_bOpen)		{			//If we are disconnecting, just pretend all the bytes were sent			return((ssize_t)len);		}		//I like to yield whenever waiting for things...		//this is optional and may not suit your implementation!		Thread::yield();	}	return(nSent);}bool SampleSocketPort::WriteData(const char *szTxData, const size_t nByteCount){	//First calculate how many bytes we are to send	ssize_t nLen = nByteCount;	if(nLen == -1)		nLen = (ssize_t)strlen(szTxData);	size_t nBytesToSend = nLen;	while(m_bOpen && nLen)	{		nLen -= DoSend((void *)&(szTxData[nBytesToSend - nLen]), nLen);	}//	If we are sending a terminator.....uncomment the following lines//	char chTerminator = '\n';// 	while(DoSend((void *)&chTerminator, 1) != 1);	return(true);}#define WITH_EXAMPLE#ifdef WITH_EXAMPLE/************ THE FOLLOWING CODE DEMONSTRATES THE USE OF THE ABOVE CLASS ******************** **** ****	To test it, compile with: ****		 ****   g++ SampleSocketPort.cpp -lccgnu -lpthread -ldl -oSampleSocketPort -ggdb -I/usr/local/include/cc++/ ****	Run the program. ****	 ****	From another terminal telnet to port 3999 of the server ****	 ****		'telnet localhost 3999' ****		 ****	Anything you type should be sent back to you in reverse! ****	 ****	To test the corrupt data detection, send a control code (like ^D), ****	if the terminating charcters are not detected within the specified time ****	the receive timeout will occur. ****	 ****///define the following to include the example classes and functionsint g_nOpenPorts = 0;			//Dirty global to allow us to quit simplyclass ReverserPort : public SampleSocketPort{public:	ReverserPort(SocketService *pService, TCPSocket & tcpSocket) : 			SampleSocketPort(pService, tcpSocket)	{		g_nOpenPorts++;	}	virtual ~ReverserPort()	{		g_nOpenPorts--;	}	virtual void OnConnectionClosed(void)	{ cerr << "Connection Closed!" << endl;	}	/**	 *	Called when a 'packet' of data has been received.	 *	This implementation simply reverses all the data and sends it back	 */	virtual void OnDataReceived(char *pszData, unsigned int nByteCount)	{		//Reverse the data and send it back		size_t nLen = strlen(pszData);		char *szToSend = new char[nLen+1];				//No need to reverse the \r\n or \0		size_t nIndex = nLen-3;		size_t i;		for(i=0; i < nLen - 2; i++)		{			szToSend[i] = pszData[nIndex - i];		}		szToSend[i++] = '\r';		szToSend[i++] = '\n';		szToSend[nLen] = '\0';		WriteData(szToSend, nLen);		delete [] szToSend;	}};class ReverserServer : public SampleSocketServiceServer{public:	ReverserServer(InetHostAddress & machine, int port) : 			SampleSocketServiceServer(machine, port), TCPSocket(machine, port), Thread()	{	}	virtual ~ReverserServer()	{	}	virtual SocketPort *CreateSocketPort(SocketService *pService, TCPSocket & Socket)	{		return(new ReverserPort(pService, Socket));	}};int main(void){	InetHostAddress LocalHost;	LocalHost = htonl(INADDR_ANY);	ReverserServer *Server = NULL; 	try 	{		Server = new ReverserServer(LocalHost, 3999);		Server->StartServer();	}	catch(...)	{		cerr << "Failed to start server" << endl;		return(false);	}        cerr << "Waiting for connections...type \"quit\" to exit." << endl;        char cmd[255];         cin.getline(cmd, 255);        while(strcmp(cmd, "quit") != 0)        {                cin.getline(cmd, 255);        }         Server->StopServer();        delete Server;	return 0;	}#endif 	//WITH_EXAMPLE

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -