浅析Symbian SocketEngine 接口代码

by  程序(code) /Kyle 

 

估计大家都想念Win32的Socket API, 或者 *nix 的Socket API吧,如果你开始Symbian编程。Win32下有一堆的Socket操作接口,以及各种模式的。Select模型,异步,完成端口,MFC封装的 两个Socket类。这些东东用的久了,也就大致忘记了其他手段了。*nix下,就是可以用用ePoll方式。本质上也算异步的控制翻转。下面是 Symbian的socket代码实例,一睹为快,其中的中文是偶加的,另外修改了其代码缩进风格。

/* Copyright (c) 2001, Nokia. All rights reserved */

#ifndef __SOCKETSENGINE_H__
#define __SOCKETSENGINE_H__

#include <in_sock.h>
#include "TimeOutNotifier.h"
#include "EngineNotifier.h"
#include "Sockets.hrh"

class CSocketsReader;
class CSocketsWriter;
class CTimeOutTimer;
class MUINotifier;

// Socket需要一个Engine类来支撑各个接口,下面的就是这个Engine的接口声明
// 因为SocketEngine需要回调,所以继承了 CActive,
// 因为需要通知超时事件,所以也实现接口 MTimeOutNotifier,
// 以及一些想知道Engine发生了什么事情的代码需要的接口 MEngineNotifier

/*!
@class CSocketsEngine

@discussion This class is the main engine part of the sockets application.
It establishes a TCP connection using its server name and port number (performing a DNS lookup
operation first, if appropriate).
It creates instances of separate active objects to perform reading from, and writing to, the socket.
*/
class CSocketsEngine : public CActive, public MTimeOutNotifier, public MEngineNotifier
{
public: // new methods
/*!
@function NewL

@discussion Create a CSocketsEngine object
@param aConsole console to use for ui output
@result a pointer to the created instance of CSocketsEngine
*/
static CSocketsEngine* NewL(MUINotifier& aConsole);

/*!
@function NewLC

@discussion Create a CSocketsEngine object
@param aConsole console to use for ui output
@result a pointer to the created instance of CSocketsEngine
*/
static CSocketsEngine* NewLC(MUINotifier& aConsole);

/*!
@function ~CSocketsEngine

@discussion Destroy the object and release all memory objects
*/
~CSocketsEngine();

/*!
@function ConnectL

@discussion Initiate connection of socket, using iServerName and iPort
*/
void ConnectL();

/*!
@function Disconnect

@discussion Disconnect socket
*/
void Disconnect();

/*!
@function WriteL

@discussion Write data to socket
@param aData data to be written
*/
void WriteL(const TDesC8& aData);

// 不是真正的读取Socket数据,而是触发 SocketReader 这个 Active Object,
// 真正能够读取数据的操作在 SocketReader 的 RunL中
/*!
@function Read

@discussion Initiate read of data from socket
*/
void Read();

/*!
@function SetServerName

@discussion Set name of server to connect to
@param aName new server name
*/
void SetServerName(const TDesC& aName);

/*!
@function ServerName

@discussion Get server name
@result name of server
*/
const TDesC& ServerName() const;

/*!
@function SetPort

@discussion Set port number to connect to
@param aPort new port number
*/
void SetPort(TInt aPort);

/*!
@function Port

@discussion Get port number
@result port number
*/
TInt Port() const;

/*!
@function Connected

@discussion Is socket fully connected?
@result true if socket is connected
*/
TBool Connected() const;

public: // from MTimeOutNotifier
/*!
@function TimerExpired

@discussion The function to be called when a timeout occurs
*/
void TimerExpired();

public: // from MEngineNotifier
/*!
@function ReportError

@discussion Report a communication error
@param aErrorType error type
@param aErrorCode associated error code
*/
void ReportError(MEngineNotifier::TErrorType aErrorType, TInt aErrorCode);

/*!
@function ResponseReceived

@discussion Data has been received on the socket and read into a buffer
@param aBuffer the data buffer
*/
void ResponseReceived(const TDesC8& aBuffer);

protected: // from CActive
/*!
@function DoCancel

@discussion cancel any outstanding operation
*/
void DoCancel();

/*!
@function RunL

@discussion called when operation complete
*/
void RunL();

private: // New methods
/*!
@function CSocketsEngine

@discussion Perform the first phase of two phase construction
@param aConsole the console to use for ui output
*/
CSocketsEngine(MUINotifier& aConsole);

/*!
@function ConstructL

@discussion Perform the second phase construction of a CSocketsEngine
*/
void ConstructL();

/*!
@function ConnectL

@discussion initiate a connect operation on a socket
@param aAddr the ip address to connect to
*/
void ConnectL(TUint32 aAddr);

/*!
@enum TSocketsEngineState

@discussion Tracks the state of this object through the connection process
@value ENotConnected The initial (idle) state
@value EConnecting A connect request is pending with the socket server
@value EConnected A connection has been established
@value ELookingUp A DNS lookup request is pending with the socket server
*/
enum TSocketsEngineState
{
ENotConnected,
EConnecting,
EConnected,
ELookingUp
};

/*!
@function ChangeStatus

@discussion handle a change in this object's status
@param aNewStatus new status
*/
void ChangeStatus(TSocketsEngineState aNewStatus);

/*!
@function Print

@discussion display text on the console
@param aDes text to display
*/
void Print(const TDesC& aDes);

private: // Member variables

/*! @const The maximum time allowed for a lookup or connect requests to complete */
static const TInt KTimeOut;

/*! @const The initial port number displayed to the user */
static const TInt KDefaultPortNumber;

/*! @var this object's current status */
TSocketsEngineState iEngineStatus;

/*! @var console for displaying text etc */
MUINotifier& iConsole;

/*! @var the actual socket */
RSocket iSocket;

/*! @var active object to control reads from the socket */
CSocketsReader* iSocketsReader;

/*! @var active object to control writes to the socket */
CSocketsWriter* iSocketsWriter;

/*! @var the socket server */
RSocketServ iSocketServ;

/*! @var DNS name resolver */
RHostResolver iResolver;

/*! @var The result from the name resolver */
TNameEntry iNameEntry;

/*! @var The anme record found by the resolver */
TNameRecord iNameRecord;

/*! @var timer active object */
CTimeOutTimer* iTimer;

/*! @var The address to be used in the connection */
TInetAddr iAddress;

/*! @var port number to connect to */
TInt iPort;

/*! @var server name to connect to */
TBuf<KMaxServerNameLength> iServerName;
};

#endif // __SOCKETSENGINE_H__


从上面的代码可以看出,SocketEngine在接口设计上,完整的体现了Symbian系统的设计风格和倾向。

1. 把各个任务切成各个 Active Object 来完成。
2. Active Object 内部一般都需要自己保留状态机以及其他的信息,来保证在RunL被调用的时候,知道自己在做什么。
3. M接口类的使用和使用。尽量使用组合的方式使用接口,除非当前类需要给其他模块提供接口的时候,才采用继承的方式实现接口。例如,其中的 SocketWriter和SocketReader是使用组合的方式,因为外部模块不需要了解Reader和Writer。外部接口希望知道的是 MEngineNotifier 所声明的接口,所以,SocketEngine实现了这个接口,但是其实是由SocketReader和SocketWriter在RunL或者其他实现 中调用的。
4. Active Object 实际上就是“回调”函数,只不过OO化了。在使用和设计上,有些违反人类的常规思路。比如简单的建立socket连接,需要在RunL中对 Scheduler的反馈的数据进行分析才可以做到。而不是简单的阻塞的方式。这个说明,这种模型是完全OO化的异步模型。希望能降低所有的计算开销。把 轮询等等操作都内化实现在Kernel中,不需要用户代码进行管理。这样的结果就是,用户代码的模型被紧密的耦合在Symbian的Active Object上,选择权的丧失,而且违反直觉。呵呵~

你可能感兴趣的:(function,server,socket,object,Symbian,construction)