📄 engine.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 + -