免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: waruqi
打印 上一主题 下一主题

[C] tbox新增stackless协程支持 [复制链接]

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
51 [报告]
发表于 2017-02-08 19:08 |只看该作者
本帖最后由 zylthinking 于 2017-02-08 19:14 编辑
yulihua49 发表于 2017-02-08 18:26
计算机技术发展至今,哪有神技?

本来,一个线程池服务器,8个线程(8核)并不需要协程与AIO。



我没说错你啊
你之前在强调你是成千上万个协程下省了协程占用的 栈内存,  但实际上是使用任务池之类的东西来绕过了每个客户端一协程来缩减协程数量; 说白了, 你的代码成功的地方是提供给了上层代码一个同步的假象, 在下面使用 poll 的方式把事情办了, 所以不用改代码了; 而不是找出了一个大量协成下能够省内存的法子

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
52 [报告]
发表于 2017-02-08 19:14 |只看该作者
本帖最后由 yulihua49 于 2017-02-08 19:21 编辑
zylthinking 发表于 2017-02-08 19:08
我没说错你啊
你之前在强调你是成千上万个协程下省了协程占用的 栈内存,  但实际上是使用任务池之类 ...

准确说叫“栈池”。
写一个任务池的异步应用比同步应用复杂多了。你接手的每个应用系统都要写个任务池吗?重复开发重复造轮子?通过协程技术,把异步操作同步化,极大的简化了应用程序的开发。
你可以看到这段代码与任何应用无关,仅仅资源管理。所以这是个通用框架,其后每个网络服务器应用都使用这个框架。就这个短短的代码调试了4个月之久,其间不断的莫名其妙的BUG。到现在算是成熟了。你不可能每个项目这么搞一遍,那样开发效率何在?这技术必须是个通用件,开发一次,长期使用。


论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
53 [报告]
发表于 2017-02-08 19:16 |只看该作者
yulihua49 发表于 2017-02-08 19:14
写一个异步的应用比同步应用复杂多了。通过协程技术,把异步操作同步化,极大的简化了应用程序的开发。
...



没说你的代码不好; 我说的是你之前的帖子有误导
你看看你之前说的:

在服务器中,依然存在上万的协程(每个连接一个协程),但是不完整,在他们不活动时不配给栈。
只有这个连接收到请求时(epoll激活后),有一个线程接收了这个事件,才分配给他一个栈。然后进行NIO和业务处理。这个服务完成后线程收回栈,以便给下一个协程使用。
系统有N个工作线程,每个线程有两个栈,一个是线程自己的栈,一个是给应用协程的栈。这样,系统只需2N个栈。圆满解决问题。

我就问你,   依然存在上万的协程 的情况下, 你占用的内存真的是 2N个栈?

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
54 [报告]
发表于 2017-02-08 19:24 |只看该作者
本帖最后由 yulihua49 于 2017-02-08 19:39 编辑

回复 53# zylthinking


2N+同时进入AIO(yield)状态的任务数。栈空间需求是概率性的(原来的栈需求是必然性的)。低概率的内存需求可以通过虚存技术解决。实际上每天同时进入AIO的任务数不超过几十个,持续时间几分钟,压力测试进行了20多分钟。在很多任务在低速网进行大数据传输时,虚存的调度时间应该不是问题。实存与虚存的比例可以依据概率计算出来。


你再看看50楼,我改了点。
我的系统安排了10000个task,实际同时进入连接状态的几百个,而实际使用栈峰值不超过30个。一天里绝大多数时间真是2N。
线程栈与协程栈使用相同的栈尺寸参数,由配置文件设定。





论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
55 [报告]
发表于 2017-02-08 19:38 |只看该作者
本帖最后由 zylthinking 于 2017-02-08 19:43 编辑

回复 54# yulihua49

我的系统安排了10000个task,实际进入连接状态的几百个,而实际使用栈峰值不超过30个。一天里绝大多数时间真是2N

这是因为你并存的 task 少,  而不是能够在并存 10000 个协程的时候, 占了 2N个栈
你首先把连接数量和协程数量分开再说吧, 你所谓的每连接一协程是不存在的; 你的就是每task一协程; 所以才能在大量连接的情况下有较少的并发协程数量

什么物理内存虚拟内存, 不干这里的事

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
56 [报告]
发表于 2017-02-08 19:41 |只看该作者
本帖最后由 yulihua49 于 2017-02-08 19:50 编辑
zylthinking 发表于 2017-02-08 19:38
回复 54# yulihua49

我的系统安排了10000个task,实际进入连接状态的几百个,而实际使用栈峰值不超过30 ...

完全可以并存10000个,甚至更多,最大是65535,就是个配置参数。压力测试做过10000个并存。
物理、虚存问题,当你对问题有了更深刻的认识后再讨论,现在可以不管。

配置多少TASK都可以,他们都不含栈,所以也占不了多少空间。
65535主要是系统fd数量限制,每个task至少一个fd。

实际连接的客户端数是你的资源限制。
你从程序里可以看到,连接了,没发请求,也是没有栈的。一般任务,发个请求,0.几秒就干完了,栈也就收回了。使用栈的任务,也就是一瞬间的事。

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
57 [报告]
发表于 2017-02-08 19:50 |只看该作者
回复 56# yulihua49

你并发的是 10000 个连接, 不是 10000 个协程;  你的每个协程都是在获得任务时创建的; 然后在处理完毕后 free;  

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
58 [报告]
发表于 2017-02-08 19:51 |只看该作者
本帖最后由 yulihua49 于 2017-02-08 19:57 编辑
zylthinking 发表于 2017-02-08 19:50
回复 56# yulihua49

你并发的是 10000 个连接, 不是 10000 个协程;  你的每个协程都是在获得任务时创建 ...

也可以这么说。但是协程的其他数据结构都是在的,唯独没有栈。
所以这个叫“协程池”,或者“栈池”都可以。

或者,NB一点,叫做“自适应的协程池”。池里,资源的数量可动态收放,最少是2N。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
59 [报告]
发表于 2017-02-08 20:16 |只看该作者
本帖最后由 yulihua49 于 2017-02-08 20:19 编辑
zylthinking 发表于 2017-02-08 19:50
回复 56# yulihua49

你并发的是 10000 个连接, 不是 10000 个协程;  你的每个协程都是在获得任务时创建 ...

并发AIO的出现条件如此苛刻,以至于除非特别设计的测试案例,普通的应用场景和测试场景,AIO极难出现,基本就是2N。
我不相信你能设计一个系统,应用期间,会出现10000个CONTEXT,同时进入AIO状态。真是这样很可能你的系统因为其他原因而运行不下去。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
60 [报告]
发表于 2017-02-08 20:25 |只看该作者
本帖最后由 yulihua49 于 2017-02-08 20:29 编辑
zylthinking 发表于 2017-02-08 19:38
回复 54# yulihua49

我的系统安排了10000个task,实际进入连接状态的几百个,而实际使用栈峰值不超过30 ...

cat AIO_tcp.c
  1. [/font][/align][align=left][font=Menlo]/**********************************************[/font][/align][align=left][font=Menlo] * @(#) SDBC 7.1 TCP RECV/SEND  Tools                      *[/font][/align][align=left][font=Menlo] * to suport coroutine[/font][/align][align=left][font=Menlo] **********************************************/[/font][/align][align=left][font=Menlo]#include <sys/socket.h>[/font][/align][align=left][font=Menlo]#include <sys/time.h>[/font][/align][align=left][font=Menlo]#include <unistd.h>[/font][/align][align=left][font=Menlo]#include <fcntl.h>[/font][/align][align=left][font=Menlo]#include <sc.h>[/font][/align]
  2. [align=left][font=Menlo]#ifndef MIN[/font][/align][align=left][font=Menlo]#define MIN(a,b) ((a)<(b))?(a):(b)[/font][/align][align=left][font=Menlo]#endif[/font][/align]
  3. [align=left][font=Menlo]static T_YIELD yield=NULL;[/font][/align]
  4. [align=left][font=Menlo]T_YIELD get_yield()[/font][/align][align=left][font=Menlo]{[/font][/align][align=left][font=Menlo]        return yield;[/font][/align][align=left][font=Menlo]}[/font][/align]
  5. [align=left][font=Menlo]T_YIELD set_yield(T_YIELD new_yield)[/font][/align][align=left][font=Menlo]{[/font][/align][align=left][font=Menlo]T_YIELD oldyield=yield;[/font][/align][align=left][font=Menlo]        yield=new_yield;[/font][/align][align=left][font=Menlo]        return oldyield;[/font][/align][align=left][font=Menlo]}[/font][/align]
  6. [align=left][font=Menlo]//timeout for second [/font][/align][align=left][font=Menlo]int RecvNet(int socket,char *buf,int n,int timeout)[/font][/align][align=left][font=Menlo]{[/font][/align][align=left][font=Menlo]int bcount=0,br,ret;[/font][/align][align=left][font=Menlo]int i,repeat=0;[/font][/align][align=left][font=Menlo]int fflag=-1;[/font][/align]
  7. [align=left][font=Menlo]        if(socket<0) return SYSERR;[/font][/align][align=left][font=Menlo]        if(!buf && n<0) return 0;[/font][/align][align=left][font=Menlo]        if(yield) {[/font][/align][align=left][font=Menlo]                fflag=fcntl(socket,F_GETFL,0);[/font][/align][align=left][font=Menlo]                if(fflag!=-1) fcntl(socket,F_SETFL,fflag|O_ASYNC|O_NONBLOCK); //异步操作[/font][/align][align=left][font=Menlo]        } else if(timeout>0) {[/font][/align][align=left][font=Menlo]                struct timeval tmout;[/font][/align][align=left][font=Menlo]                tmout.tv_sec=timeout;[/font][/align][align=left][font=Menlo]                       tmout.tv_usec=0;[/font][/align][align=left][font=Menlo]                       ret=setsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,(char *)&tmout,sizeof(tmout));[/font][/align][align=left][font=Menlo]                if(ret) ShowLog(1,"%s:setsockopt errno=%d,%s",__FUNCTION__,errno,strerror(errno));[/font][/align][align=left][font=Menlo]        }[/font][/align]
  8. [align=left][font=Menlo]        *buf=0;[/font][/align][align=left][font=Menlo]        br=0;[/font][/align]
  9. [align=left][font=Menlo]        while(bcount<n){[/font][/align][align=left][font=Menlo]                if((br=read(socket,buf,n-bcount))>0){[/font][/align][align=left][font=Menlo]                        bcount+=br;[/font][/align][align=left][font=Menlo]                        buf+=br;[/font][/align][align=left][font=Menlo]                        repeat=0;[/font][/align][align=left][font=Menlo]                        continue;[/font][/align][align=left][font=Menlo]                }[/font][/align][align=left][font=Menlo]                if(fflag==-1 && errno==EAGAIN) return TIMEOUTERR;[/font][/align][align=left][font=Menlo]                if(br<=0 && errno && errno != EAGAIN){[/font][/align][align=left][font=Menlo]                    if(errno!=ECONNRESET)[/font][/align][align=left][font=Menlo]                        ShowLog(1,"%s:br=%d,err=%d,%s",__FUNCTION__,br,errno,strerror(errno));[/font][/align][align=left][font=Menlo]                    break;[/font][/align][align=left][font=Menlo]                }[/font][/align][align=left][font=Menlo]                if(bcount < n && fflag!=-1) { //切换任务[/font][/align][align=left][font=Menlo]                        if(repeat++>3) return -errno;[/font][/align][align=left][font=Menlo]/*[/font][/align][align=left][font=Menlo]yield:[/font][/align][align=left][font=Menlo]1.找到当前线程的context。找不到返回-1;(后续任务以同步阻塞完成)[/font][/align][align=left][font=Menlo]2.把事件提交给epoll,作为resume的条件。[/font][/align][align=left][font=Menlo]3.swapcontext,挂起这个任务,线程回到epoll_wait,可以为别人服务了。[/font][/align][align=left][font=Menlo]4.一旦这个任务的事件发生了,立即由epoll_wait激活一个线程,抓取相应的context,使用setcontext,恢复任务现场,返回0.[/font][/align][align=left][font=Menlo]后续的动作就是继续NONBLOCK的IO。直至完成返回。[/font][/align][align=left][font=Menlo]*/[/font][/align][align=left][font=Menlo]ShowLog(5,"%s:tid=%lx,socket=%d,yield to schedle bcount=%d/%d",__FUNCTION__,pthread_self(),socket,bcount,n);[/font][/align][align=left][font=Menlo]                        i=yield(socket,0,timeout);[/font][/align][align=left][font=Menlo]                        if(i<0) {[/font][/align][align=left][font=Menlo]                          if(timeout>0) {[/font][/align][align=left][font=Menlo]                                struct timeval tmout;[/font][/align][align=left][font=Menlo]                                tmout.tv_sec=timeout;[/font][/align][align=left][font=Menlo]                                tmout.tv_usec=0;[/font][/align][align=left][font=Menlo]                                ret=setsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,(char *)&tmout,sizeof(tmout));[/font][/align][align=left][font=Menlo]                          }[/font][/align][align=left][font=Menlo]                                fcntl(socket,F_SETFL,fflag);[/font][/align][align=left][font=Menlo]                                fflag=-1;[/font][/align][align=left][font=Menlo]                                if(i==TIMEOUTERR) return i;[/font][/align][align=left][font=Menlo]                        }[/font][/align][align=left][font=Menlo]                }[/font][/align][align=left][font=Menlo]        }[/font][/align][align=left][font=Menlo]        if(fflag!=-1) fcntl(socket,F_SETFL,fflag);[/font][/align][align=left][font=Menlo]        return bcount==0?-1:bcount;[/font][/align][align=left][font=Menlo]}[/font][/align]
  10. [align=left][font=Menlo]int SendNet(int socket,char *buf,int n,int MTU)[/font][/align][align=left][font=Menlo]{[/font][/align][align=left][font=Menlo]int bcount,bw;[/font][/align][align=left][font=Menlo]int sz,i=0;[/font][/align][align=left][font=Menlo]int fflag=-1;[/font][/align][align=left][font=Menlo]size_t SendSize;[/font][/align]
  11. [align=left][font=Menlo]        if(socket<0) return SYSERR;[/font][/align][align=left][font=Menlo]        if(yield) {[/font][/align][align=left][font=Menlo]                fflag=fcntl(socket,F_GETFL,0);[/font][/align][align=left][font=Menlo]                if(fflag != -1) fcntl(socket,F_SETFL,fflag|O_NONBLOCK); //异步操作[/font][/align][align=left][font=Menlo]        }[/font][/align][align=left][font=Menlo]        bcount=0;[/font][/align][align=left][font=Menlo]        bw=0;[/font][/align][align=left][font=Menlo]        if(MTU>500) SendSize=MTU;[/font][/align][align=left][font=Menlo]        else SendSize=n;[/font][/align][align=left][font=Menlo]        while(bcount<n){[/font][/align][align=left][font=Menlo]                sz=MIN(n-bcount,SendSize);[/font][/align][align=left][font=Menlo]                if((bw=write(socket,buf,sz))>0){[/font][/align][align=left][font=Menlo]                        bcount+=bw;[/font][/align][align=left][font=Menlo]                        buf+=bw;[/font][/align][align=left][font=Menlo]                }[/font][/align][align=left][font=Menlo]                if(bw<0&&errno!=EAGAIN) {[/font][/align][align=left][font=Menlo]                        ShowLog(1,"%s:err=%d,%s",__FUNCTION__,errno,strerror(errno));[/font][/align][align=left][font=Menlo]                        break;[/font][/align][align=left][font=Menlo]                }[/font][/align][align=left][font=Menlo]                if(bw < sz && fflag != -1) { //切换任务[/font][/align][align=left][font=Menlo]//ShowLog(5,"%s:tid=%lx,socket=%d,yield bw=%d/%d",__FUNCTION__,pthread_self(),socket,bw,sz);[/font][/align][align=left][font=Menlo]                    i=yield(socket,1,0); [/font][/align][align=left][font=Menlo]                    if(i<0) {[/font][/align][align=left][font=Menlo]                        fcntl(socket,F_SETFL,fflag);[/font][/align][align=left][font=Menlo]                        fflag = -1;[/font][/align][align=left][font=Menlo]                    }[/font][/align][align=left][font=Menlo]                }[/font][/align][align=left][font=Menlo]        }[/font][/align][align=left][font=Menlo]        if(fflag != -1)  fcntl(socket,F_SETFL,fflag);[/font][/align][align=left][font=Menlo]        return bcount==0?-1:bcount;[/font][/align][align=left][font=Menlo]}[/font][/align]
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP