Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1029318
  • 博文数量: 177
  • 博客积分: 3629
  • 博客等级: 中校
  • 技术积分: 1839
  • 用 户 组: 普通用户
  • 注册时间: 2005-02-23 21:21
文章分类

全部博文(177)

文章存档

2021年(1)

2020年(5)

2019年(4)

2018年(7)

2017年(1)

2016年(4)

2014年(1)

2013年(8)

2012年(10)

2011年(50)

2009年(12)

2008年(10)

2006年(56)

2005年(8)

分类: C/C++

2006-04-07 23:35:49


SocketHandle类分析

 
类用途:
负责select调用,管理多个SOCKET,封装FD_SET,FD_ISSET之类的操作,调用Socket函数中定义的回调函数。新加线程安全.
可以说,此类是执行官。别的类做具体工作,它负责调配。
基础:
下面要用到的结构:
typedef std::list socket_v;
从定义来看,是一SOCKET的集合,分开保存一些不同类型的SOCKET,如可读的,可写的。
typedef std::map socket_m;
这是原始SOCKET和Socket *(类指针)的组合,用map类最合适.
对上述两种结构C++标准程序库里有详细介绍.
 
注: 偶只对Select()方法中用到的一些熟悉,有些如socks4协议之类的和线程安全有关的东东还没弄透。这儿把偶用过的写下来。

一些保护变量:
protected:
 socket_m m_sockets; ///< Active sockets list
 socket_m m_add; ///< Sockets to be added to sockets list
 std::list m_delete; ///< Sockets to be deleted (failed when Add)
 
一些私有变量:
private:
StdLog *m_stdlog; ///< Registered log class, or NULL
 SOCKET m_maxsock; ///< Highest file descriptor + 1 in active sockets list
 fd_set m_rfds; ///< file descriptor set monitored for read events
 fd_set m_wfds; ///< file descriptor set monitored for write events
 fd_set m_efds; ///眼熟吧。这三个变量和select模式中的是一样的。
#ifdef _WIN32
 int m_preverror; ///< debug select() error
#endif
 bool m_slave; ///< Indicates that this is a SocketHandler run in SocketThread
//下面带socks4字样的用于socks4协议,具体上cnpaf.net去看
 ipaddr_t m_socks4_host; ///< Socks4 server host ip
 port_t m_socks4_port; ///< Socks4 server port number
 std::string m_socks4_userid; ///< Socks4 userid
 bool m_bTryDirect; ///< Try direct connection if socks4 server fails
// 
int m_resolv_id; ///< Resolver id counter
 ResolvServer *m_resolver; ///< Resolver thread pointer
 port_t m_resolver_port; ///< Resolver listen port
 bool m_b_enable_pool; ///< Connection pool enabled if true
//下面几个老外写的清楚,怕偶翻译了反而有人不明白,不过SOCKET多了,象这样分开保存也是必要的。
 socket_v m_fds; ///< Active file descriptor list
 socket_v m_fds_erase; ///< File descriptors that are to be erased from m_sockets
 socket_v m_fds_callonconnect; ///< checklist CallOnConnect
 socket_v m_fds_detach; ///< checklist Detach
 socket_v m_fds_connecting; ///< checklist Connecting
 socket_v m_fds_retry; ///< checklist retry client connect
 socket_v m_fds_close; ///< checklist close and delete
//互斥体,用于多线程,线程安全,不过偶还没用到。用到了再来补充。
 Mutex& m_mutex; ///< Thread safety mutex
 bool m_b_use_mutex; ///< Mutex correctly initialized
 
最关键的函数是Select(),共有三个,其实只有
int SocketHandler::Select(struct timeval *tsel)
这一个是真正执行的.
真正的Select代码分析已在中写过.
 
在<之一>上main里的函数有通用性.
首选声明一个SocketHandler对象,如h,再声明一个继承自Socket类的对象(如TcpSocket,一般是自定义类,重载方法,可以从TcpSocket,HttpGetSocket,HttpSocket继承,当然直接从Socket类继承也可以,不过TcpSocket类的好处就享受不到了^_^),假设是mysocket,下一步可以进行下面的方法了:
h.add(&mysocket);
最后,写个select循环,就可以了.循环结束,不出错的话,我们所需要的都完成了.
 
先说说m_sockets,m_add,m_delete这三个结构
先看add方法,用到了m_add,m_delete.
add方法一般是必用的(在TcpSocket级别上而不是HttpGetSocket级别上)
void SocketHandler::Add(Socket *p)
{
if (p -> GetSocket() == INVALID_SOCKET)
 {                  //如果SOCKET无效,m_delete会保存这个类指针
  if (p -> CloseAndDelete())
  {
   m_delete.push_back(p);
  }
  return;
 }
m_add[p -> GetSocket()] = p; //把包含有效SOCKET的Socket类指针保存在m_add里
}
注意到Select函数开头有一段:
while (m_add.size())
{
  socket_m::iterator it = m_add.begin();
  SOCKET s = (*it).first;
  Socket *p = (*it).second;
  //省略若干验证,处理......
  m_fds.push_back(s); //这句在下面m_fds处有说明
  m_sockets[s] = p;  //此处m_sockets增加元素
  m_add.erase(it)    //而m_add相应的删除这个
}
说明m_add 与m_sockets有一定的关系.
对于一个已初始化的类来说,先加入m_add容器,Select调用时,检查是否在m_sockets容器中存在,如不存在,则加入m_sockets容器.无论存在不存在,都将从m_add容器中删除此类指针.
 
下面看看变量 m_fds,类似的有几个,以这一个为例.
在上面的Select调用中,有一句:
m_fds.push_back(s);
只在Select调用的开始处有这么一句.所有的可用SOCKET都将保存到这个容器中.下面的FD_ISET还要对这个容器的元素进行论循.所以这是个很重要的结构.
m_fds_*这类的还有几个,分别包含不同类别的SOCKET,用于其他的用途.举一例:
if( m_fds_callonconnect.size() )
{
  //在这里会对m_fds_callonconnect的元素论循.对每一个SOCKET 进行如下操作
/****************开始*****************************************
调用Socket::SetConnected();设定已连接状态为真
如果此SOCKET所在Socket类缓冲区有数据,则调用TcpSocket::OnWrite发送数据
如果重连接标志已设立,调用Socket::OnReconnect(),否则调用Socket::OnConnect(),这都是定义好的回调函数,(用虚函数实现的)
*************************************************************/
}
再重复一下,这个
Socket::OnConnect()
对于使用者来说只需重载它,看偶<之一>的代码是调用了SendBuf(),发出自己的GET请求.
 
待续
阅读(2685) | 评论(0) | 转发(0) |
0

上一篇:Socket库分析之三

下一篇:Socket库分析之五

给主人留下些什么吧!~~