Javen-Studio 咖啡小屋

http://javenstudio.org/ - C++ Java 分布式 搜索引擎 - Naven's Research Laboratory - Thinking of Life, Imagination of Future

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  24 随笔 :: 52 文章 :: 117 评论 :: 4 Trackbacks

SOCKET 的封装

C++ 通用框架的设计 作者: naven

1           SOCKET 封装介绍

Socket 通讯程序估计现在大多数应用系统都会涉及到,因为现在的世界是一个由 Internet 网络连接的世界,任何个人电脑或服务都可能会有数据交换,通过 TCP/UDP 这样的 Socket 通讯协议进行联系。开发这样的通讯程序会是很普遍也很类似,每种操作系统都实现了 Socket 通讯库并提供很相似的 API ,通讯步骤都遵循 RFC 规范。但是有些 API 的具体接口却稍有不同,比如 Socket IO API win32 系统和 Unix 系统就不一样, Win32 recv/send Unix 使用标准统一的 read/write ,而且 socket 句柄在不同操作系统处理也不一样,等等这些都造成编写跨平台的 Socket 应用不太容易。另外编写服务器和客户端的处理步骤也很繁琐, IP 地址和域名的转换也很麻烦,所以实现一个标准统一使用更简洁的 API 非常有用。本 C++ 框架基本参考 Java Socket 相关类实现了类似封装,除了 ServerSocket 实现稍有不同,其他原理和方法基本类似。用它编写网络应用基本不用考虑底层的协议处理,使用非常容易,代码也更简洁易读。

 

主要有如下一些类

 

class Socket                                                    代表一个 TCP 连接的 Socket 对象

         class DatagramSocket                                    代表一个 UDP 连接的 Socket 对象(暂未实现)

         class MulticastSocket                                    一个 DatagramSocket 的子类用于多播(暂未实现)

class SocketAcceptor                                    一个 TCP 服务端的接收器

class SocketConnector                                  一个 TCP 客户端的连接器

         class SocketInputStream                               一个 Socket 连接的输入流

         class SocketOutputStream                            一个 Socket 连接的输出流

         class SocketReader                                        一个 Socket 连接的读操作器

         class SocketWriter                                          一个 Socket 连接的写操作器

 

Socket 的意思是在网络的机器之间建立一个通信线路。通过 TCP Sockets 发送或接收的操作时通过 InputStream OutputStream 流处理的, Socket 类的 getInputStream getOutputStream 可以取得该 Socket 连接的输入 / 输出流对象。 SocketAcceptor 是用于服务器端的接收器,它处于接收的状态时会阻塞,直到接收到客户端的连接请求,这时就会创建一个 Socket 对象代表该服务器到此客户端的连接。而对应的 SocketConnector 是用于客户端的连接器,它向服务端发出连接请求,如果服务器允许连接,则也同时建立一个 Socket 对象表示它到服务器端的连接,这时就可以获取输入 / 输出流对象进行 Socket 通讯了。

2           Hello World!

下面的程序示例如何用上面的类进行 Scoket 通讯:

这是服务端的实现

void  servertest() 
{
    
//  定义一个接收器绑定 8000 端口
    SocketAcceptor sa( 8000 ); 
    
while ( 1
{
       
//  阻塞等待连接请求
        Socket sk  =  sa.accept(); 
        
//  获取此连接的读操作器和写操作器
        Reader  & rd  =  sk.getReader(); 
        Writer 
& wr  =  sk.getWriter(); 
        String s; 
        
//  从客户端读取 10 个字节
        rd.read(s,  10 ); 
        
//  向客户端写信息
        wr.write(“read ok”); 
        
//  关闭连接
        sk.close(); 
}

}

这是客户端的实现

void  clienttest()
{
    
//  定义一个连接器
SocketConnector sc; 
//  连接指定的服务器地址及端口, 返回一个Socket对象
Socket sk  =  sc.connect(“localhost”,  8000 ); 
//  如果已成功连上
     if ( sk.isConnected() ) 
{
    
//  获取此连接的读操作器和写操作器
        Reader &  reader  =  sk.getReader(); 
        Writer
&  writer  =  sk.getWriter(); 
        
//  可以在读操作器上建立一个带缓冲的读操作器
        BufferedReader rd(reader);
        
//  向服务器发送信息
        writer.write(“hello server”);
        
//  接收信息, 带缓冲的读操作器可以读取一行
        rd.readLine(s);
        
//  关闭连接
        sk.close();
    }

}


1           Socket

此类定义一个表示 Socket 连接的类,一个 Socket 是一个为在两台机器间通信的端点。一个 Socket 类的真实行为是通过一个 SocketImpl 类的诗体执行的。一个应用程序可以通过改变 Socket Factory 来创建 Socket 的具体实现,以适应本地的局域网防火墙。

Socket 类成员和主要接口定义如下:

 

class  Socket :  public  AbstractFile 
{
protected
    
/* *
     * The implementation of this Socket.
     
*/

    SocketImplAutoPtr _impl; 

    
/* *
     * Various states of this socket.
     
*/

    BOOL _connected; 
    BOOL _closed; 
    BOOL _shutIn; 
BOOL _shutOut;

public
    
/* *
     * Creates an unconnected socket, with the
     * system-default type of SocketImpl.
     
*/

Socket();

    
/* *
     * Returns an input stream for this socket.
     *
     * @return     an input stream for reading bytes from this socket.
     
*/

    InputStream
&  getInputStream();

    
/* *
     * Gets an Reader for this socket.
     
*/

    Reader
&  getReader();

    
/* *
     * Returns an output stream for this socket.
     *
     * @return     an output stream for writing bytes to this socket.
     
*/

    OutputStream
&  getOutputStream();

    
/* *
     * Gets an Writer for this socket.
     
*/

    Writer
&  getWriter(); 

    
/* *
     * Enable/disable the option specified by <I>optID</I>.  If the option
     * is to be enabled, and it takes an option-specific "optval",  this is
     * passed in <I>value</I>.  The actual type of value is option-specific,
     * and it is an error to pass something that isn't of the expected type:
     * <BR>
     *
     * @param optID identifies the option
     * @param level [in] Level at which the option is defined; the supported levels 
     *              include SOL_SOCKET and IPPROTO_TCP. 
     * @param optval [in] Pointer to the buffer in which the value for the requested 
     *              option is to be returned.
     * @param optlen [in] Pointer to the size of the optval buffer, in bytes. 
     * @return 0 If no error occurs, Otherwise, a value of SOCKET_ERROR(-1) is returned, 
     *          and a specific error code can be retrieved by socketerrno.
     * @see #getOption(int)
     
*/

    
int  setOption( int  optID,  int  level,  const   void   * optval,  int  optlen);

    
/* *
     * Fetch the value of an option.
     * Binary options will return java.lang.Boolean(true)
     * if enabled, java.lang.Boolean(false) if disabled, e.g.:
     * <BR>
     *
     * @param optID an <code>int</code> identifying the option to fetch
     * @param level [in] Level at which the option is defined; the supported levels 
     *              include SOL_SOCKET and IPPROTO_TCP. 
     * @param optval [out] Pointer to the buffer in which the value for the requested 
     *              option is to be returned.
     * @param optlen [in, out] Pointer to the size of the optval buffer, in bytes. 
     * @return 0 If no error occurs, Otherwise, a value of SOCKET_ERROR(-1) is returned, 
     *          and a specific error code can be retrieved by socketerrno.
     * @see #setOption(int, java.lang.Object)
     
*/

    
int  getOption( int  optID,  int  level,  void   * optval,  int   * optlen);

    
/* *
     * Closes this socket.
     * <p>
     * Any thread currently blocked in an I/O operation upon this socket
     * will throw a {@link SocketException}.
     * <p>
     * Once a socket has been closed, it is not available for further networking
     * use (i.e. can't be reconnected or rebound). A new socket needs to be
     * created.
     *
     * <p> If this socket has an associated channel then the channel is closed
     * as well.
     *
     
*/

    
void  close();

}
;


 

1           SocketAcceptor

此类实现一个用于服务器端接收连接的类。一个SocketAcceptor对象等待来自网络的连接请求,它执行一些基于请求的操作,并且可能返回一些信息给请求者。连接成功后SocketAcceptor会生成一个Socket对象用于网络通讯。

SocketAcceptor类成员和主要接口定义如下:

 

class SocketAcceptor
{
protected
    
/**
     * The factory for all server sockets.
     
*/

    
static SocketImplFactoryAutoPtr _factory; 

    
/**
     * The implementation of this Socket.
     
*/

    SocketImplAutoPtr _impl; 

    
/**
     * Various states of this socket.
     
*/

    BOOL _bound; 
    BOOL _created; 
    BOOL _closed; 
    BOOL _stream; 

public
    
/**
     * Creates a socket acceptor with default stream type.
     * <p>
     
*/

    SocketAcceptor(); 

    
/**
     * Creates a socket acceptor with specified stream type, 
     * bound to the specified port and host. A port of 
     * <code>0</code> creates a socket on any free port. 
     * <p>
     * The maximum queue length for incoming connection indications (a 
     * request to connect) is set to <code>50</code>. If a connection 
     * indication arrives when the queue is full, the connection is refused.
     * <p>
     * If the application has specified a server socket factory, that 
     * factory's <code>createSocketImpl</code> method is called to create 
     * the actual socket implementation. Otherwise a "plain" socket is created.
     * <p>
     *
     * @param      host the host address the server will bind to
     * @param      port  the port number, or <code>0</code> to use any
     *                   free port.
     * @param      stream    if <code>true</code>, create a stream socket;
     *                       otherwise, create a datagram socket.
     * @param      backlog the listen backlog
     
*/

SocketAcceptor(
const String &host, int port, BOOL stream = TRUE);

    
/**
     * Binds the <code>ServerSocket</code> to a local address
     * (IP address and port number).
     * <P>
     * The <code>backlog</code> argument must be a positive
     * value greater than 0. If the value passed if equal or less
     * than 0, then the default value will be assumed.
     * @param port the local TCP port
     * @param backlog the listen backlog
     * @return 0 If no error occurs, Otherwise, a value of 
     *          SOCKET_ERROR(-1) is returned
     
*/

    
int bind(int port, int backlog = LISTENQ);

    
/**
     * Listens for a connection to be made to this socket and accepts 
     * it. The method blocks until a connection is made. 
     *
     * <p>A new Socket <code>s</code> is created and, if there 
     * is a security manager, 
     * the security manager's <code>checkAccept</code> method is called
     * with <code>s.getInetAddress().getHostAddress()</code> and
     * <code>s.getPort()</code>
     *
     * @param timeout  timeout to accept in ms. 
     * @return the new Socket
     
*/

    Socket accept(
int timeout); 

    
/**
     * Closes this socket acceptor.
     * <p>
     * Any thread currently blocked in an I/O operation upon this socket
     * will throw a {@link SocketException}.
     * <p>
     * Once a socket has been closed, it is not available for further networking
     * use (i.e. can't be reconnected or rebound). A new socket needs to be
     * created.
     *
     * <p> If this socket has an associated channel then the channel is closed
     * as well.
     *
     
*/

    
void close();

}
;

1           SocketConnector

此类实现一个用于客户器端连接服务的类。一个SocketConnector对象可以向指定的服务地址和端口发出的连接请求,它执行一些基于请求的操作,并且可能返回一些信息。连接成功后SocketConnector会生成一个Socket对象用于网络通讯。

SocketConnector类成员和主要接口定义如下:

class SocketConnector
{
protected
    
/**
     * The factory for all server sockets.
     
*/

    
static SocketImplFactoryAutoPtr _factory; 

    
/**
     * The implementation of this Socket.
     
*/

    SocketImplAutoPtr _impl; 

    
/**
     * Various states of this socket.
     
*/

    BOOL _bound; 
    BOOL _created; 
    BOOL _closed; 
    BOOL _stream;; 

public
    
/**
     * Creates a socket connector with specified stream type.
     * default is Creates a stream socket connector. 
     * <p>
     *
     * @param      stream    if <code>true</code>, create a stream socket;
     *                       otherwise, create a datagram socket.
     
*/

    SocketConnector(BOOL stream 
= TRUE);

    
/**
     * Creates a socket and connects it to the specified port on
     * the specified host.
     * @param host the specified host
     * @param port the specified port
     * @param timeout the timeout value in milliseconds, or zero for no timeout.
     *          -1 will use default timeout.
     * @return the new Socket
     
*/

Socket connect(
const String &host, int port, int timeout = -1);

    
/**
     * Closes this socket connector.
     * <p>
     * Any thread currently blocked in an I/O operation upon this socket
     * will throw a {@link SocketException}.
     * <p>
     * Once a socket has been closed, it is not available for further networking
     * use (i.e. can't be reconnected or rebound). A new socket needs to be
     * created.
     *
     * <p> If this socket has an associated channel then the channel is closed
     * as well.
     *
     
*/

    
void close();

}
;

1           SocketInputStream

这个类类似与其他InputStreamFileInputStream类,是InputStream接口类的一个实现,执行Socket流的读取操作,实现的接口均是最基础的操作,如读取一个byte字节的数据,或者读取指定长度的数据。

SocketInputStream类成员和主要接口定义如下:

class SocketInputStream : public InputStream