Socket模拟Http连接 之 初识Socket

来源:互联网 发布:异域狂想曲 知乎 编辑:程序博客网 时间:2024/05/21 09:32

在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);

原创粉丝点击