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

📄 engine.cpp

📁 基于symbian的收发SMS、MMS消息
💻 CPP
字号:
////////////////////////////////////////////////////////////////
//
//    engine.cpp
//
//    Copyright (C) 2001, Forum Nokia - The Developer Community
//
//
////////////////////////////////////////////////////////////////

#include <e32base.h>
#include "tcpudp.h"
#include "engine.h"

const TInt KTimeOut = 15000000; // 30 seconds time-out

/**************************************************
	Class constructor
**************************************************/
CRunEngine::CRunEngine(): CActive(EPriorityHigh), iRecData(0,0), iSendData(0,0)   
{
}
/*************************************************/


/**************************************************
	Class destructor
**************************************************/
CRunEngine::~CRunEngine()
{
	Cancel();
	iSocketServer.Close();
	if (iRecBuffer != 0)
	{	
		delete iRecBuffer;
		iRecBuffer = 0;
	}	
	if (iSendBuffer != 0)
	{	
		delete iSendBuffer;
		iSendBuffer = 0;
	}
    delete iMyTimer;
}
/**************************************************/



/**************************************************
	Second phase constructor
**************************************************/
void CRunEngine::ConstructL(CTcpUdpView *aAppView)
{
	iAppView    = aAppView;
	iSendBuffer = 0;
	iRecBuffer  = 0;
	
	iState = EIdle;
	CActiveScheduler::Add(this);	//Adds itself to the scheduler

    //Default values
	TPreferences preferences;
	DefaultPreferences(preferences);
	
    iProtocol    = preferences.iProtocol;
	iRemotePort  = preferences.iRemotePort;
	iRemoteAddr.Copy(preferences.iRemoteAddr);
	
	iLocalPort   = preferences.iLocalPort;
	iLocalAddr.Copy(preferences.iLocalAddr);
	
	iCount       = preferences.iCount;
	iTrace       = preferences.iTrace;
	iPacketSize  = preferences.iPacketSize;
	
    // Timer
    iMyTimer = new(ELeave) CMyTimer;
	iMyTimer->ConstructL(this);

    /*
		The client has to open a session with the ESOCK server by
		calling the Connect() method of the RSocketServ class. The
		connected socket server will be used later in the Start() 
		method for opening a socket.

	*/
	
	// Connect() may leave
	CleanupStack::PushL(iMyTimer);

    TInt err = iSocketServer.Connect();
    if (err != KErrNone)
    {
        User::Panic(_L("Cannot open session with the ESOCK server!"), err);
    }

	CleanupStack::Pop();

}
/*************************************************/



/**************************************************
	Function: specifies default values

**************************************************/
void CRunEngine::DefaultPreferences(TPreferences &aPref)
{
	//Default values
	aPref.iProtocol    = UDP;
	aPref.iRemotePort  = 7;
	aPref.iRemoteAddr  = _L("127.0.0.1");
	aPref.iLocalPort   = 2080;
	aPref.iLocalAddr   = _L("127.0.0.1");
	aPref.iCount       = 1000;
	aPref.iTrace       = EFalse ;
	aPref.iPacketSize  = 10 ;
}
/*************************************************/



/**************************************************
	Function: passes current setting values

**************************************************/
void CRunEngine::GetPreferences(TPreferences &aPref)
{
	aPref.iProtocol    = iProtocol;

	aPref.iRemotePort  = iRemotePort;
	aPref.iRemoteAddr.Copy(iRemoteAddr);

	aPref.iLocalPort   = iLocalPort;
	aPref.iLocalAddr.Copy(iLocalAddr) ;

	aPref.iCount       = iCount;
	aPref.iTrace       = iTrace;
	aPref.iPacketSize  = iPacketSize;
}
/*************************************************/



/**************************************************
	Function: sets new setting values

**************************************************/
void CRunEngine::SetPreferences(TPreferences &aPref)
{
	iProtocol         = aPref.iProtocol;
	iRemotePort       = aPref.iRemotePort;
	iRemoteAddr.Copy(aPref.iRemoteAddr) ;
	iLocalPort        = aPref.iLocalPort;
	iLocalAddr.Copy(aPref.iLocalAddr);
	iCount            = aPref.iCount;
	iTrace            = aPref.iTrace;
	iPacketSize       = aPref.iPacketSize;
}
/*************************************************/



/**************************************************
	Function: starts the sending/receiving process

**************************************************/
TInt CRunEngine::Start()
{	
	TInt err = KErrNone;

	if (iPacketSize == 0)
		iPacketSize = 1;
	
	if (iSendBuffer != 0)
		delete iSendBuffer;
	
	// Create the sent packet with 1 extra byte for zero terminate
	iSendBuffer = HBufC8::NewL(iPacketSize+1);
	iSendData.Set(iSendBuffer->Des());
	// Initialize send data buffer
	iSendData.FillZ();
	iSendData.Zero();

	// dummy character in sending packet
	TChar xChar = 'X';
	// just fill the packet with dummy characters
	iSendData.Fill(xChar, iPacketSize-1);
	// Currently the Echoserver reads coming data till it receives a 
	// newline character. This is recognized as the end of each packet.
	TChar nl = '\n';
	iSendData.Append(nl);
	iSendData.ZeroTerminate();

	if (iRecBuffer != 0)
		delete iRecBuffer ;
	/* 
		Because the echoserver will send back the same data with the same 
		size, we create a received buffer with its length is equal to 
		the sent packet's size. Otherwise the size can be arbitrarily set.
	*/
	// Allocate memory for the receiving buffer
	iRecBuffer = HBufC8::NewL(iPacketSize+1);
	TPtr8 auxPtr(( TUint8* )iRecBuffer->Des().Ptr(), iPacketSize);
	iRecData.Set(auxPtr);
	
	// reset other necessary parameters
	iState          = EIdle;
	iRecvPackets    = 0;
	iSentPackets    = 0;
	iTotalBytesRcvd = 0;


	/*
		Initialize the remote host parameters by setting its
		port and IP address
	*/
	iSendAddr.SetPort(iRemotePort);     // remote port
	iSendAddr.Input(iRemoteAddr) ;      // remote address

	// set the local port
	iRecAddr.SetPort(iLocalPort);       // own port

	// make sure address family is correct
	if (iSendAddr.Family() == KAfInet)
	{
		// own address IPv4
		iRecAddr.Input(iLocalAddr) ;		  
		iAppView->Write(_L("\nUsing IPv4 addresses."));
	}
	// this sample application does not support IPv6 address
	else
	{
		iAppView->Write(_L("\nNot support IP type."));
		return -1;
	}

	/*
		open a socket according to protocol type for sending/receiving data
	*/
	if (iProtocol == TCP)
		err = iSocket.Open(	iSocketServer,	 // The socket server session 
							KAfInet,		 // Constant for a protocol family 
							KSockStream,	 // Stream socket
							KProtocolInetTcp // Constant which identifies the TCP protocol 
							);
	else
		err = iSocket.Open(	iSocketServer,	 // The socket server session
							KAfInet,		 // Constant for a protocol family
							KSockDatagram,	 // Datagram socket
							KProtocolInetUdp // Constant which identifies the UDP protocol
							);
	
	// checking Open()'s returned value
    if (err != KErrNone)
    {
        iAppView->Write(_L("Cannot open the socket!.\n"));
        return err;
    }

	/*
		setting the local port is equivalent to calling Bind() with 
		only the port set in the address.
	*/
	err = iSocket.SetLocalPort(iLocalPort);
	if (err != KErrNone)
	{
		if (err == KErrInUse)
			iAppView->Write(_L("\nLocal port is in use.\n"));
		else	
			iAppView->Write(_L("Socket binding failed.\n"));
		return err;
	}

	/*
		For TCP sockets, an active connection is made to the remote 
		host. When the socket call completes successfully, the socket 
		is ready to send and receive data. To form a connection, 
		the protocol must establish a network interface and a route 
		to the destination. So the Connect() method is called.

	*/
	if (iProtocol == TCP)
	{
		__ASSERT_ALWAYS(!IsActive(), User::Panic(_L("CRunEngine"), 1));

		// Connect
		iSocket.Connect(iSendAddr, iStatus);
		SetActive();
				
		TBuf<80> aux;
        aux.Format(_L("\nConnecting to port %d.\n"), iRemotePort);
	    iAppView->Write(aux);
		iState = EConnected;
	}
	/*
		As UDP is a connectionless protocol, Connect() does not have to 
		be called before writing data with RSocket::SendTo(). However, 
		even for UDP Connect() can be also used to set the address for 
		all data sent from the socket, in which case Send()/Write() may 
		be used in addition to SendTo().

		In this example, SendTo() is employed so Connect() is not called
	*/
	else // UDP
	{
		TBuf<80> aux;
        aux.Format(_L("\nSending UDP packets to port %d.\n"), iRemotePort);
	    iAppView->Write(aux);

		SendPacket();
		iState = ESending;		
	}

    return KErrNone;
}
/*************************************************/



/**************************************************
	Function: cancels any socket pending process

**************************************************/
void CRunEngine::Stop()
{
	TBuf<80> aux;
	aux.Format(_L("Total number of sent packets: %d.\n"), iSentPackets);
	iAppView->Write(aux);

	// Cancel() will cause a call to DoCancel() which
	// cancels any outstanding read/write operation.
	Cancel();  
	iStatus = KErrNone;
	iState = EClosing;
	RunL();

	if (iSendBuffer != 0)
	{	
		delete iSendBuffer ;
	    iSendBuffer = 0 ;
	}

	if (iRecBuffer != 0)
	{	
		delete iRecBuffer ;
		iRecBuffer = 0 ;
	}
}
/*************************************************/



/**************************************************
	Function: handles the engine active object抯 
			  request completion event.


**************************************************/
void CRunEngine::RunL()
{
	// holding information message to print on the screen
	TBuf<80> aux;

    if (iStatus == KErrCancel || iStatus == KErrAbort)
    {	// This happens after calling cancel functions in socket
        iStatus = KErrNone;
    }
    else if (iStatus != KErrNone)
    {
        iAppView->Write(_L("Something happened.\n"));
        aux.Format(_L("RunL received iStatus = %d.\n"),iStatus);
	    iAppView->Write(aux);
        CloseSockets();
        iState = EIdle;
        iAppView->UpdateBusyMsg();		
    }

	/*
	    The asynchronous operation that has completed and we 
		check the current state of communication action.
		iState was set to engage the engine to one of the
		following states:
	*/
    else switch (iState)
    {
			// Idle status, nothing to send or receive
        case EIdle:
            break;

			// TCP connection is established
        case EConnected:
			iAppView->Write(_L("Connected.\n"));

			// Start sending the first packet
			SendPacket();
            break;

			//	a packet has been sent out
		case ESending:
			// increment the number of sent packets
			iSentPackets++ ;
			if (iTrace)
			{	
				aux.Format(_L("Sent packet number %d.\n"), iSentPackets);
				iAppView->Write(aux);
			}

			/*
				after a packet is sent, an echo packet is expected
				from the echoserver. ReceivePacket() will issue a 
				read/recv request and wait for a reply
			*/
			ReceivePacket();

			// set the timer to timeout after 15 sec if the reply from
			// the echoserver does not come.
			if (iProtocol == UDP)
				if (!iMyTimer->IsActive())
					iMyTimer->After(KTimeOut);  // 15 sec

			// Prevent inactivity-related events from occuring (blank screen)
			User::ResetInactivityTime() ;
			break;
	
			// a reply (echoed) packet has come
        case EReceiving:
			// if the reply comes while timeout is pending,
			// the timer must be cancelled
			if (iMyTimer->IsActive())
				iMyTimer->Cancel() ;

			// increment the number of received packets
			iRecvPackets++;
            
			if (iTrace)
			{
				iTotalBytesRcvd += iRecData.Length();
				aux.Format(_L("Received %d bytes. Total %d.\n"),iRecData.Length(), iTotalBytesRcvd);
				iAppView->Write(aux);
			}

			/*
				iCount is the number of packets to be sent set by a user, 
				if iCount is 0, the loop is infinity, otherwise, sending
				loop terminates when the number of echoed packets is equal
				to the value of iCount
			*/
			if ( (iCount > 0) && (iRecvPackets >= iCount) )
			{	
				Stop();
				break;
			}
			
			// call to send next packet
			SendPacket();
            break;

			// when the Stop button is clicked or all echoed packets are received
        case EClosing:
			// close the connected socket
            CloseSockets();
            iState = EIdle;
			iAppView->Write(_L("TcpUdp stopped.\n"));
			iAppView->UpdateBusyMsg();
			break;

			// any undefined state
        default:
            iAppView->Write(_L("Something is wrong, State unknown.\n"));
            iState = EIdle;
            break;
    }
}
/*************************************************/



/**************************************************
	Function: asynchronously reads/receives incoming 
	data from the socket.


**************************************************/
void CRunEngine::ReceivePacket()
{
	iRecData.Zero();

	if (iProtocol == TCP)
	{	
		iSocket.Recv(iRecData, 0, iStatus, iNumRcvd);
	}	
	else // UDP
		iSocket.RecvFrom(iRecData, iRecAddr, 0, iStatus);

	iState = EReceiving;
    SetActive();
}
/*************************************************/



/**************************************************
	Function: handles the engine active object抯 
			  request completion event.


**************************************************/
void CRunEngine::SendPacket()
{
	if (iProtocol == TCP)
	    iSocket.Send(iSendData, 0, iStatus, iNumRcvd);
	else // UDP
		iSocket.SendTo(iSendData, iSendAddr, 0, iStatus);

	// engage the engine to sending
	iState = ESending;

	SetActive();
}
/*************************************************/



/**************************************************
	Function: releases the local port then 
	close the socket.


**************************************************/
void CRunEngine::CloseSockets()
{
	// This ensures that TCP releases local port at once
	iSocket.CancelConnect();	
    iSocket.Close();
}
/*************************************************/



/**************************************************
	Function: cancels outstanding operations then 
	close the socket.


**************************************************/
void CRunEngine::DoCancel()
{
	if (iMyTimer->IsActive())
		iMyTimer->Cancel() ;
	
	
    switch (iState)
    {
    case EIdle:
    case EClosing:
		break;

	// cancel any asynchronous operations.
	case EConnected:
		iSocket.CancelAll();
        break;
	// cancel an outstanding receive operation.
    case EReceiving:
		iSocket.CancelRecv();
		break;
	// cancel an outstanding send operation
    case ESending:
        iSocket.CancelSend();
        break;

    default:
        iAppView->Write(_L("Something is really wrong, State unknown.\n"));
        iSocket.CancelAll();
        iState = EIdle;
    }
}


//
// class CMyTimer
//
CMyTimer::CMyTimer(): CTimer(0)
{}

void CMyTimer::ConstructL(CRunEngine *aEngine)
{
	CTimer::ConstructL();
	CActiveScheduler::Add(this);
    iEngine = aEngine;
}

void CMyTimer::RunL()
{
	// if timer timeouts, call Stop() to cancel any 
	// outstanding operation and retry by calling Start()
	iEngine->Stop();
	iEngine->Start();
}

⌨️ 快捷键说明

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