IPerf开源代码中Socket类

一 点睛

Socket的定义和实现分别在文件Socket.hpp和Socket.cpp。

它的主要功能是封装socket文件描述符、此Socket对应的端口号以及socket接口中的listen、accept、connect和close等函数,为用户提供了一个简单易用而又同一的接口。同时作为其他派生类的基类。

二 类定义

class Socket {
public:
    // stores server port and TCP/UDP mode
    Socket( unsigned short inPort, bool inUDP = false );

    // destructor
    virtual ~Socket();

protected:
    // get local address
    SocketAddr getLocalAddress( void );

    // get remote address
    SocketAddr getRemoteAddress( void );

    // server bind and listen
    void Listen( const char *inLocalhost = NULL, bool isIPv6 = false );

    // server accept
    int Accept( void );

    // client connect
    void Connect( const char *inHostname, const char *inLocalhost = NULL );

    // close the socket
    void Close( void );

    // to put setsockopt calls before the listen() and connect() calls
    virtual void SetSocketOptions( void ) {
    }

    // join the multicast group
    void McastJoin( SocketAddr &inAddr );

    // set the multicast ttl
    void McastSetTTL( int val, SocketAddr &inAddr );

    int   mSock;             // socket file descriptor (sockfd)
    unsigned short mPort;    // port to listen to
    bool  mUDP;              // true for UDP, false for TCP

}; // end class Socket

#endif // SOCKET_H

该类主要提供了4个函数: Listen、Accept、Connect、Close。

getLocalAddress和getRemoteAddress的作用分别是获得Socket本端的地址和对端的地址,两个地址返回一个SocketAddr实例。

SetSocketOptions的作用是设置Socket的属性,它是一个虚函数,因此不同Socket的派生类在实现此函数时会执行不同的操作。

三 类的实现

1 Listen函数

void Socket::Listen( const char *inLocalhost, bool isIPv6 ) {
    int rc;

    SocketAddr serverAddr( inLocalhost, mPort, isIPv6 );

    // create an internet TCP socket
    int type = (mUDP  ?  SOCK_DGRAM  :  SOCK_STREAM);
    int domain = (serverAddr.isIPv6() ?
#ifdef IPV6
                  AF_INET6
#else
                  AF_INET
#endif
                  : AF_INET);





    mSock = socket( domain, type, 0 );
    FAIL_errno( mSock == INVALID_SOCKET, "socket" );


    SetSocketOptions();

    // reuse the address, so we can run if a former server was killed off
    int boolean = 1;
    Socklen_t len = sizeof(boolean);
    // this (char*) cast is for old headers that don't use (void*)
    setsockopt( mSock, SOL_SOCKET, SO_REUSEADDR, (char*) &boolean, len );

    // bind socket to server address

    
    rc = bind( mSock, serverAddr.get_sockaddr(), serverAddr.get_sizeof_sockaddr());
    FAIL_errno( rc == SOCKET_ERROR, "bind" );
    
    // listen for connections (TCP only).
    // default backlog traditionally 5
    if ( ! mUDP ) {
        rc = listen( mSock, 5 );
        FAIL_errno( rc == SOCKET_ERROR, "listen" );
    }

} // end Listen

Socket的Listen方法将地址解析、socket、bind和listen等系统调用组合为一个函数。在应用时,调用一个Listen方法就可以完成Server端socket初始化的所有工作。

2 Accept函数

int Socket::Accept( void ) {
    iperf_sockaddr clientAddr;
    Socklen_t addrLen;
    int connectedSock;

    while ( true ) {
        // accept a connection
        addrLen = sizeof( clientAddr );
        connectedSock = accept( mSock, (struct sockaddr*) &clientAddr, &addrLen );

        // handle accept being interupted
        if ( connectedSock == INVALID_SOCKET  &&  errno == EINTR ) {
            continue;
        }

        return connectedSock;
    }

} // end Accept

Accept函数为Accept系统调用增添了在中断后自动重启的功能。Server线程在执行Accept函数后被阻塞,直到有请求到达,或者接收到某个信号。若是后面一种情况,Accept会返回INVALID_SOCKET,并设置 errno 为EINTR。Accept方法检查这种情况,并重新调用Accept函数。

3 Connect函数

void Socket::Connect( const char *inHostname, const char *inLocalhost ) {
    int rc;
    SocketAddr serverAddr( inHostname, mPort );

    assert( inHostname != NULL );

    // create an internet socket
    int type = (mUDP  ?  SOCK_DGRAM : SOCK_STREAM);

    int domain = (serverAddr.isIPv6() ?
#ifdef IPV6
                  AF_INET6
#else
                  AF_INET
#endif
                  : AF_INET);

    mSock = socket( domain, type, 0 );
    FAIL_errno( mSock == INVALID_SOCKET, "socket" );

    SetSocketOptions();


    if ( inLocalhost != NULL ) {
        SocketAddr localAddr( inLocalhost );


        // bind socket to local address
        rc = bind( mSock, localAddr.get_sockaddr(), localAddr.get_sizeof_sockaddr());
        FAIL_errno( rc == SOCKET_ERROR, "bind" );
    }


    // connect socket
    rc = connect( mSock, serverAddr.get_sockaddr(), serverAddr.get_sizeof_sockaddr());
    FAIL_errno( rc == SOCKET_ERROR, "connect" );

} // end Connect

Connect函数是Client端调用的函数,作用是连接指定的Server。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值