在Symbian上使用Socket需要库的支持,即你需要引入头文件es_sock.h和esock.lib库,准备一个活动对象类,比如class SocketConnection : public CActive
(1)声明RSocketServ iSocketServ;它是用来连接Symbian系统中Soket服务的类,并不是我们一般意义上的SocketServer,在Symbian中实现类似于Java中SocketServer功能的类实际上是RSocket。
(2)连接系统的Socket服务,即,iSocket.Connect();
(3)声明RSocket对象 iSocket作为一个发送请求的SocketClient。
(4) 打开连接(其实只是初始化RSocket对象,并不是真的打开了连接,连地址都没给呢,它上哪打开去啊~),即 iSocket.Open(iSocketServ,KAfInet,KSockStream,KProtocolInetTcp); 方法中参数含义为,#param1 已经连接成功的Socket服务对象,即(1)中提到的iSocketServ;#param2 KAfInet,代表该套接字为因特网套接字;#param3 KSockStream 可靠的面向连接的套接字;#param4 KProtocolInetTcp TCP控制传输协议。
(5)编写连接方法,如SocketConnect(const TDesC& aServerName,TInt aServerPort);其中#param1 主机名称;#param2 主机端口,首先判断aServerName是否为IP地址,如果是则进入连接过程,如果不是则通过DNS对主机名进行解析从而得到IP地址,无论是连接还 是解析,这两个过程都是异步的,故拦截或者取得解析结果都有在RunL中完成。判断一个主机名是不是IP地址,可以通过TInetAddr类完成,它依赖 于in_sock.h头文件和insock.lib库,具体用法如下:
TInetAddr addr;
if ( addr.Input( *m_pServerName ) == KErrNone )
{
//进入连接过程
}
else
{
进入解析过程
}
(6) 通过DNS解析主机名地址,使用RHostResolver对象,利用它的Open方法和GetByName方法即可,如 m_Resolver.Open(m_SocketServer , KAfInet , KProtocolInetUdp);此处的参数与前面RSocket的Open方法略有不同!Socket网络连接这样写就可以了。 m_Resolver.GetByName( *m_pServerName , m_NameEntry , iStatus );通过GetByName方法把参数传给RHostResolver对象内。最后SetActive()来启动活动对象。在活动对象内取得结果,具体代 码随后附上。
(7)进入连接过程,连接过程比较简单,有如下步骤:
TInetAddr addr;
addr.SetPort( m_ServerPort );
addr.SetAddress( aAddr );
m_Socket.Connect( addr , iStatus );
执行完以上步骤后就可以启动活动对象了。
通过以上步骤,我们就可以通过Socket连接某一个网站了,整个代码后面会给出,该代码只是连接部分,我们会在下一次继续介绍,如果处理Socket的读写功能。尽管现在的代码还有诸多不完善的地方,我们会在以后的讲解中一步步填充完整。
#ifndef SOCKETCONNECTION_H
#define SOCKETCONNECTION_H
// INCLUDES
#include <e32std.h>
#include <e32base.h>
#include <es_sock.h>//RSocketServ,RSocket
#include <in_sock.h>//TInetAddr
// CLASS DECLARATION
enum
{
ENotConnected, ELookingUp, EConnecting, EConnected
};
class CSocketConnection : public CActive
{
public:
~CSocketConnection( );
static CSocketConnection* NewL( );
static CSocketConnection* NewLC( );
void ConnectServer( const TDesC& aServerName , TInt aServerPort );
protected:
// from CActive
virtual void RunL( );
virtual void DoCancel( );
virtual TInt RunError( TInt aError );
private:
CSocketConnection( );
void SocketConnect(TUint32 aAddr);
void ConstructL( );
private:
RSocketServ m_SocketServer;//用于连接Symbian系统服务中的Soket服务
RSocket m_Socket;//Socket通道
RHostResolver m_Resolver;//寻找其他设备类,用来通过DNS将主机名解析为ip地址
HBufC* m_pServerName;//主机名称
TInt m_ServerPort;
TNameEntry m_NameEntry;//用来从RHostResolver中返回结果到该对象中
TInt m_ConnectStatus;
};
#endif // SOKETCONNECTION_H
#include "SocketConnection.h"
#include <bautils.h>
#include "log.h"
CSocketConnection::CSocketConnection( ) :
CActive( EPriorityStandard )
{
m_ConnectStatus = 0;
}
CSocketConnection::~CSocketConnection( )
{
m_Socket.Close( );
m_SocketServer.Close( );
m_Resolver.Close( );
delete m_pServerName , m_pServerName = NULL;
}
CSocketConnection* CSocketConnection::NewLC( )
{
CSocketConnection* self = new ( ELeave ) CSocketConnection( );
CleanupStack::PushL( self );
self->ConstructL( );
return self;
}
CSocketConnection* CSocketConnection::NewL( )
{
CSocketConnection* self = CSocketConnection::NewLC( );
CleanupStack::Pop( ); // self;
return self;
}
void CSocketConnection::ConstructL( )
{
CActiveScheduler::Add(this);
//连接服务器
m_SocketServer.Close( );
m_Socket.Close( );
LOG( _L("be ready to connect RServer(Socket)...") );
User::LeaveIfError( m_SocketServer.Connect( ) );
LOG( _L("have connected the RServer(Socket) !") );
LOG( _L("be ready to open(init) a pointer of RSocket...") );
User::LeaveIfError( m_Socket.Open(
m_SocketServer ,
KAfInet ,
KSockStream ,
KProtocolInetTcp ) );
LOG( _L("have open(init) the pointer of RSocket !") );
}
void CSocketConnection::SocketConnect( TUint32 aAddr )
{
m_Socket.Close( );
User::LeaveIfError( m_Socket.Open(
m_SocketServer ,
KAfInet ,
KSockStream ,
KProtocolInetTcp ) );
TInetAddr addr;
addr.SetPort( m_ServerPort );
addr.SetAddress( aAddr );
m_Socket.Connect( addr , iStatus );
m_ConnectStatus = EConnecting;
SetActive( );
}
void CSocketConnection::ConnectServer( const TDesC& aServerName , TInt aServerPort )
{
if(m_ConnectStatus != ENotConnected)
return;
delete m_pServerName , m_pServerName = NULL;
if ( aServerName.Length( ) > 0 )
{
m_pServerName = aServerName.Alloc( );
}
else
{
m_pServerName = _L("").Alloc( );
}
m_ServerPort = aServerPort;
if ( m_pServerName->Length( ) <= 0 )
{
LOG( _L("the ServerName is empty !") );
return;
}
LOG( _L("ServerName is [%S]") , m_pServerName );
LOG( _L("ServerPort is [%d]") , m_ServerPort );
//通过TInetAddr来判断aServerName是否为IP地址
//如果是ip地址,则直接进入连接过程
//如果不是ip地址,则进入解析过程,通过RHostResolver类将主机名称解析为ip地址
TInetAddr addr;
if ( addr.Input( *m_pServerName ) == KErrNone )
{
//进入连接过程
SocketConnect( addr.Address( ) );
}
else
{
LOG( _L("the ServerName is not a IP address !") );
LOG( _L("be ready to parse ServerName [%S] to IP adress !") ,m_pServerName );
m_Resolver.Close( );
m_Resolver.Open( m_SocketServer , KAfInet , KProtocolInetUdp );
m_Resolver.GetByName( *m_pServerName , m_NameEntry , iStatus );
m_ConnectStatus = ELookingUp;
SetActive( );
}
}
void CSocketConnection::DoCancel( )
{
m_Socket.Close( );
m_Resolver.Close( );
}
TInt CSocketConnection::RunError( TInt aError )
{
return 0;
}
void CSocketConnection::RunL( )
{
switch ( m_ConnectStatus )
{
case EConnecting :
{
if ( iStatus == KErrNone )//连接成功
{
m_ConnectStatus = EConnected;//状态置为已连接状态
}
else//连接不成功,状态置为未连接状态
{
m_ConnectStatus = ENotConnected;
}
break;
}
case ELookingUp :
{
//搜寻其他设备或连接地址,在Soket应用中,时常需要判断给出的主机地址名是否为一个IP地址,如果不是则需要进行对主机名称解析為IP地址
m_Resolver.Close( );
if ( iStatus == KErrNone )//状态无错误,则证明解析地址成功
{
TNameRecord nameRecord = m_NameEntry( );
TBuf < 15 > address;
TInetAddr::Cast( nameRecord.iAddr ).Output( address );
m_ConnectStatus = ENotConnected;
//进入连接过程
SocketConnect( TInetAddr::Cast( nameRecord.iAddr ).Address( ) );
LOG(_L("Get IP Address [%S]->[%S] sucessfuly !"),m_pServerName ,
&address );
}
else
{
m_ConnectStatus = ENotConnected;
LOG(
_L("Can not get IP address from ServerName [%S]"),m_pServerName );
}
break;
}
}
}
具体使用方法:
m_pSocketConn = CSocketConnection::NewL();
m_pSocketConn->ConnectServer(_L("mail.163.com"),80);