导航:首页 > 源码编译 > getchannel源码解析

getchannel源码解析

发布时间:2022-09-08 11:42:41

❶ netty3.6.2中写数据的过程,以及写数据写不出去后怎么处理

netty写数据的时候,会先放到一个缓存队列AbstractNioChannel.writeBufferQueue中,这个队列是WriteRequestQueue
java代码
public void eventSunk(
ChannelPipeline pipeline, ChannelEvent e) throws Exception {
if (e instanceof ChannelStateEvent) {
……
} else if (e instanceof MessageEvent) {
MessageEvent event = (MessageEvent) e;
NioSocketChannel channel = (NioSocketChannel) event.getChannel();
boolean offered = channel.writeBufferQueue.offer(event);//写到channel的writeBufferQueue
assert offered;
channel.worker.writeFromUserCode(channel);
}
}
WriteRequestQueue的offer方法中会根据缓存消息的总大小(字节数)判断是否超过了高水位线highWaterMark,如果第一次超过了超过高水位线,就会fireChannelInterestChanged;后边如果仍然一直往队列放数据,缓存的消息的大小持续超过高水位线的时候,不会再fireChannelInterestChanged。
Java代码
public boolean offer(MessageEvent e) {
boolean success = queue.offer(e);
assert success;

int messageSize = getMessageSize(e);
int newWriteBufferSize = writeBufferSize.addAndGet(messageSize);
int highWaterMark = getConfig().getWriteBufferHighWaterMark();

if (newWriteBufferSize >= highWaterMark) {
if (newWriteBufferSize - messageSize < highWaterMark) {
highWaterMarkCounter.incrementAndGet();
if (!notifying.get()) {
notifying.set(Boolean.TRUE);
fireChannelInterestChanged(AbstractNioChannel.this);
notifying.set(Boolean.FALSE);
}
}
}
return true;
}
fireChannelInterestChanged这个会调到SimpleChannelUpstreamHandler.handleUpstream,触发SimpleChannelUpstreamHandler.channelInterestChanged,可以通过继承这个方法来自定义做些事情。高水位的值可以通过Bootstrap设置,最终会调到DefaultNioSocketChannelConfig.setOption。writeBufferHighWaterMark默认值为64K
Java代码
public boolean setOption(String key, Object value) {
if (super.setOption(key, value)) {
return true;
}
if ("writeBufferHighWaterMark".equals(key)) {
setWriteBufferHighWaterMark0(ConversionUtil.toInt(value));
} else if ("writeBufferLowWaterMark".equals(key)) {
setWriteBufferLowWaterMark0(ConversionUtil.toInt(value));
} else if ("writeSpinCount".equals(key)) {
setWriteSpinCount(ConversionUtil.toInt(value));
} else if ("".equals(key)) {
(() value);
} else if ("receiveBufferSizePredictor".equals(key)) {
setReceiveBufferSizePredictor((ReceiveBufferSizePredictor) value);
} else {
return false;
}
return true;
}
然后在write0的时候会从队列拉数据,拉数据的时候,如果发现本次拉的数据会导致缓存的数据大小(字节)从低水位writeBufferLowWaterMark之上,掉到了低水位之下,即跨过了低水位,会再次触发fireChannelInterestChanged事件。writeBufferLowWaterMark默认值为32K
Java代码
public MessageEvent poll() {
MessageEvent e = queue.poll();
if (e != null) {
int messageSize = getMessageSize(e);
int newWriteBufferSize = writeBufferSize.addAndGet(-messageSize);
int lowWaterMark = getConfig().getWriteBufferLowWaterMark();


if (newWriteBufferSize == 0 || newWriteBufferSize < lowWaterMark) {
if (newWriteBufferSize + messageSize >= lowWaterMark) {//本次拉取,是的缓存数据大小掉到了低水位之下
highWaterMarkCounter.decrementAndGet();
if (isConnected() && !notifying.get()) {
notifying.set(Boolean.TRUE);
fireChannelInterestChanged(AbstractNioChannel.this);
notifying.set(Boolean.FALSE);
}
}
}
}
return e;
}
超过高水位和低于低水位都会触发fireChannelInterestChanged,怎么区分呢?通过AbstractChannel. isWritable(),如果channel的interestOps里边有注册过OP_WRITE,则是不可写的,否则是可写的
Java代码
public boolean isWritable() {
return (getInterestOps() & OP_WRITE) == 0;
}
public int getInterestOps() {
if (!isOpen()) {
return Channel.OP_WRITE;
}

int interestOps = getRawInterestOps();
int writeBufferSize = this.writeBufferSize.get();
if (writeBufferSize != 0) {
if (highWaterMarkCounter.get() > 0) {//还记得这个值,放数据到发送队列的时候值+=1,从队列拉数据出来的时候值-=1
int lowWaterMark = getConfig().getWriteBufferLowWaterMark();
if (writeBufferSize >= lowWaterMark) {//缓存队列数据量,超过高水位,也超过了低水位,意味着高水位>低水位,此时等于注册写操作
interestOps |= Channel.OP_WRITE;
} else {
interestOps &= ~Channel.OP_WRITE;//缓存队列数据量,超过高水位但是低于低水位,意味着低水位>高水位,此时等于没有注册写操作
}
} else {//超过高水位counter<=0,意味着当前数据量小于高水位
int highWaterMark = getConfig().getWriteBufferHighWaterMark();
if (writeBufferSize >= highWaterMark) {//这里,缓存数据量仍然高于高水位.....并发?按道理说channel的处理是单线程处理的,此时等于注册写操作
interestOps |= Channel.OP_WRITE;
} else {
interestOps &= ~Channel.OP_WRITE;
}
}
} else {
interestOps &= ~Channel.OP_WRITE;//写队列没数据,没有注册写操作
}

return interestOps;
}
即,如果超过高水位isWritable()==false,低于低水位isWritable()==true,低水位优先级高于高水位,即如果 当前水位>低水位 则不可写,否则可写

如果在通过netty向某机器写数据,但是写很缓慢,则会导致数据都缓存到netty的发送队列中,如果不做控制,可能会导致full gc/cms gc频繁,甚至最终OOM。所以可以考虑用高水位和低水位的值来控制netty的缓存队列,即用AbstractChannel.isWritable来控制是否继续写,如果AbstractChannel.isWritable==false,则丢弃数据,或者记录发送数据的状态,待后续缓存数据队列水位下降到安全水位后再发送。

❷ 用java实现pdf转jpg图片的全代码,我这里附上参考代码。

学JAVA就到广州疯狂JAVA来学习 李刚授课 我是不能。。。

❸ 做seo懂代码还是很好的,分享一点关于KesionCMS的调用代码

======网站通用标签==============
{$GetSiteTitle} 显示网站标题
{$GetSiteName} 显示网站名称
{$GetSiteLogo} 显示网站logo(不带参数)
{=GetLogo(130,90)} 显示网站logo(带参数,logo的宽和高)
{=GetTags(1,10)}热门Tags
{=GetTags(2,10)}访问时间排序
{=GetTags(3,10)}添加时间排序
{$GetSiteCountAll}显示网站信息统计(栏目总数,文章总数….)
{$GetSiteOnline}显示在线人数(总在线:X人 用户:X人; 游客:X人)
{=GetTopUser(5,more...)}显示活跃用户排行5条
{=GetUserDynamic(10)}显示用户动态(大家都在做什么)最近更新前10条
{$GetSpecial}显示专题入口
{$GetFriendLink}显示友情链接入口
{$GetSiteUrl}显示网站URL
{#GetFullDomain}显示网站完整URL(不管有没有启用相对路径,始终返回完整域名) ---- NEW
{$GetInstallDir}显示网站安装路径
{$GetManageLogin}显示管理入口
{$GetCopyRight}显示版权信息
{$GetMetaKeyWord}显示针对搜索引擎的关键字
{$GetMetaDescript}显示针对搜索引擎的描述
{$GetWebmaster}显示站长
{$GetWebmasterEmail}显示站长Email
{$GetClubInstallDir} 论坛安装目录
{$TodayGroupbuyLink}获得今日团购URL
{$HistoryGroupbuyLink}获得往期团购URL
{$GetTemplateDir}模板路径
{$GetCssDir}CSS路径
=====常用脚本特效标签=========
{=JS_Ad("左联Flash地址","右联Flash地址","/images/close.gif",0.8)} 对联广告
{$JS_Time1}时间特效(样式:2006年4月8日)
{$JS_Time2}时间特效(样式:2006年4-月8日 星期六)
{$JS_Time3}时间特效(样式:2007年6月1日 星期五 [农历 4月初五])
{$JS_Time4}时间特效(样式:2006年4月8日 11:50:46 星期六)
{$JS_Language}简繁转换
{$JS_HomePage}设为首页
{$JS_Collection}加入收藏
{$JS_ContactWebMaster}联系站长
{$JS_GoBack}返回上一页
{$JS_WindowClose}关闭窗口
{$JS_NoSave}页面不被别人”另存为”
{$JS_NoIframe}页面不被别人放到框架中
{$JS_NoCopy}防止网页信息被复制
{$JS_DCRoll}双击滚屏特效
{=JS_Status1("请在这里输入要显示的文字",120)} 状态栏打字效果
{=JS_Status2("请在这里输入要显示的文字",120)} 文字在状态栏上从右往左循环显示效果
{=JS_Status3("请在这里输入要显示的文字",150)} 文字在状态栏上打字之后移动消失效果
==========系统函数标签(KesionCMS入门标签)=============
系统函数标签是用户自己在后台标签管理系统函数标签里面创建的标签,标签名称由自己命名。
调用方式{LB_标签名称};
常用标签如下所示:
{LB_频道导航} {LB_网站公告} {LB_友情链接} {LB_位置导航} {LB_相关文章} {LB_终级文章列表}
=============会员系统专用标签=================
{$GetUserLoginByScript}显示会员登录入口(Script调用)
{$GetPopLogin}显示会员登录入口(跳窗)
{$GetTopUserLogin} 显示会员登录入口(横排)
{$GetUserLogin}显示会员登录入口(竖排)
{$GetAllUserList}显示所有注册会员列表(仅限使用于会员列表页模板)
{$GetUserRegLicense}显示新会员注册服务条款和声明
{$Show_UserNameLimitChar}显示新会员注册时用户名最少字符数
{$Show_UserNameMaxChar}显示新会员注册时用户名最多字符数
{$Show_VerifyCode}显示新会员注册时验证码
{$GetUserRegResult}新会员注册成功信息
=============搜索专用标签==============
{$GetSearchByDate} 高级日历搜索(小插件)
{$GetSearch} 总站搜索
{$GetArticleSearch}文章系统搜索
{$GetPhotoSearch}图片系统搜索
{$GetDownLoadSearch}下载系统搜索
{$GetFlashSearch}动漫系统搜索
{$GetShopSearch}商城系统搜索
{$GetMovieSearch}影视系统搜索
{$GetSupplySearch}供求系统搜索
{$GetesfSearch}二手房源搜索
{$GetzfSearch}出租房源搜索
===========频道(栏目)专用标签===============
{$GetChannelID} 显示当前模型ID
{$GetChannelName}显示当前模型名称
{$GetItemName}显示当前模型的项目名称
{$GetItemUnit}显示当前模型的项目单位
{$GetClassID}显示当前栏目ID
{$GetClassName}显示当前栏目名称
{$GetClassUrl}显示当前栏目链接地址
{$GetClassPic}显示当前栏目图片
{$GetClassIntro}显示当前栏目介绍
{$GetClass_Meta_KeyWord}针对搜索引擎的关键字
{$GetClass_Meta_Description}针对搜索引擎的描述
{$GetParentID}显示父栏目ID
{$GetParentUrl}显示父栏目链接地址
{$GetParentClassName}显示父栏目名称
======================================内容页标签====================================
==========文章内容页标签(以下标签仅适用于文章内容页)=============
{$GetArticleUrl} 当前文章URL
{$ChannelID}当前模型ID
{$InfoID}当前文章小ID
{$ItemName}当前项目名称
{$ItemUnit}当前项目单位
{$GetArticleShortTitle}文章简短标题
{=GetPhoto(130,90)}内容页图片(宽*高)
{$GetArticleTitle}完整标题
{$GetArticleKeyWord}关键字Tags
{$GetKeyTags}取得文章Tags
{$GetArticleIntro}文章导读
{$GetArticleContent}文章内容
{$GetArticleAuthor}文章作者
{$GetArticleOrigin}文章来源
{$GetArticleDate}添加日期(格式:2009年5月1日)
{$GetDate} 添加日期(直接输出)
{$GetHits}文章人气(总浏览数)
{$GetHitsByDay}文章本日浏览数
{$GetHitsByWeek}文章本周浏览数
{$GetHitsByMonth}文章本月浏览数
{$GetArticleInput}文章录入(带链接)
{$GetUserName}文章录入(不带链接)
{$GetRank}文章推荐等级
{$GetArticleProperty}显示文章的属性(热门、推荐、滚动…)
{$GetArticleSize}显示文章[字体:大 中 小]
{$GetArticleAction}显示[发表评论] [告诉好友] [打印文章]
{$GetPrevArticle}显示上一篇文章
{$GetNextArticle}显示下一篇文章
{$GetPrevUrl}显示上一篇文章URL
{$GetNextUrl}显示下一篇文章URL
{$GetShowComment}显示评论
{$GetWriteComment}发表评论

❹ {$Field(1,GetChannel,3)}

获取字段的,具体获得什么不知道,不知道你这个从哪读的数据源

❺ java中getchannel的含义和具体用法。

getChannel()是得到FileChannel类的一种方法,只有FileInputStream/FileOutputStream/RandomAccessFile对象有getChannel()方法;
比如:FileChannel fc = new FileOutputStream("data.txt").getChannel();

❻ 怎么将一个channel的数据发送给另一个channel

5.不同通道channel之间传输数据

在Java的NIO中,如果两个通道中有一个是FileChannel,那么我们可以直接将数据从一个channel传输到另外一个channel中。两个通道之间传输数据的方式有两种,分别是:
- transferFrom()
- transferTo()

5.1 transferFrom()

FileChannel 的transferFrom()方法可以将数据从源通道传输到FileChannel中(这个方法在JDK文档中解释为将字节从给定的可读取字节通道传输到此通道的文件中)。下面是一个简单的例子:

RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
FileChannel fromChannel = fromFile.getChannel();//获取source的通道;

RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");
FileChannel toChannel = toFile.getChannel();//获取dest的通道;

long position = 0;
long count = fromChannel.size();

long result = toChannel.transferFrom(fromChannel, position, count);

LogUtil.log_debug(""+result);
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
方法的输入参数
- position表示从position处开始向目标文件写入数据,
- count表示最多传输的字节数。如果源通道的剩余空间小于count个字节,则所传输的字节数要小于请求的字节数。

此外要注意,在SoketChannel的实现中,SocketChannel只会传输此刻准备好的数据(可能不足count字节)。因此,SocketChannel可能不会将请求的所有数据(count个字节)全部传输到FileChannel中。

5.2 transferTo()方法

transferTo()方法将数据从FileChannel传输到其他的channel中。下面是一个简单的例子:

RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
FileChannel fromChannel = fromFile.getChannel();//获取source的通道;

RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");
FileChannel toChannel = toFile.getChannel();//获取dest的通道;

long position = 0;
long count = fromChannel.size();
long result = fromChannel.transferTo(position, count, toChannel);
LogUtil.log_debug(""+result);
1
2
3
4
5
6
7
8
9
10

1
2
3
4
5
6
7
8
9
10
观察一下就可以发现,其实这两个例子其实非常的相似,如果仅仅从文件IO的角度来看,就是两个文件之间的数据复制;

上面所说的关于SocketChannel的问题在transferTo()方法中同样存在。SocketChannel会一直传输数据直到目标buffer被填满。

❼ channelhandlercontext getchannel.getid;在哪个jar包里面

1、Client向Server发送http请求。 2、Server端对http请求进行解析。 3、Server端向client发送http响应。 4、Client对http响应进行解析。

❽ Android socket源码解析(三)socket的connect源码解析

上一篇文章着重的聊了socket服务端的bind,listen,accpet的逻辑。本文来着重聊聊connect都做了什么?

如果遇到什么问题,可以来本文 https://www.jianshu.com/p/da6089fdcfe1 下讨论

当服务端一切都准备好了。客户端就会尝试的通过 connect 系统调用,尝试的和服务端建立远程连接。

首先校验当前socket中是否有正确的目标地址。然后获取IP地址和端口调用 connectToAddress 。

在这个方法中,能看到有一个 NetHooks 跟踪socket的调用,也能看到 BlockGuard 跟踪了socket的connect调用。因此可以hook这两个地方跟踪socket,不过很少用就是了。

核心方法是 socketConnect 方法,这个方法就是调用 IoBridge.connect 方法。同理也会调用到jni中。

能看到也是调用了 connect 系统调用。

文件:/ net / ipv4 / af_inet.c

在这个方法中做的事情如下:

注意 sk_prot 所指向的方法是, tcp_prot 中 connect 所指向的方法,也就是指 tcp_v4_connect .

文件:/ net / ipv4 / tcp_ipv4.c

本质上核心任务有三件:

想要能够理解下文内容,先要明白什么是路由表。

路由表分为两大类:

每个路由器都有一个路由表(RIB)和转发表 (fib表),路由表用于决策路由,转发表决策转发分组。下文会接触到这两种表。

这两个表有什么区别呢?

网上虽然给了如下的定义:

但实际上在Linux 3.8.1中并没有明确的区分。整个路由相关的逻辑都是使用了fib转发表承担的。

先来看看几个和FIB转发表相关的核心结构体:

熟悉Linux命令朋友一定就能认出这里面大部分的字段都可以通过route命令查找到。

命令执行结果如下:

在这route命令结果的字段实际上都对应上了结构体中的字段含义:

知道路由表的的内容后。再来FIB转发表的内容。实际上从下面的源码其实可以得知,路由表的获取,实际上是先从fib转发表的路由字典树获取到后在同感加工获得路由表对象。

转发表的内容就更加简单

还记得在之前总结的ip地址的结构吗?

需要进行一次tcp的通信,意味着需要把ip报文准备好。因此需要决定源ip地址和目标IP地址。目标ip地址在之前通过netd查询到了,此时需要得到本地发送的源ip地址。

然而在实际情况下,往往是面对如下这么情况:公网一个对外的ip地址,而内网会被映射成多个不同内网的ip地址。而这个过程就是通过DDNS动态的在内存中进行更新。

因此 ip_route_connect 实际上就是选择一个缓存好的,通过DDNS设置好的内网ip地址并找到作为结果返回,将会在之后发送包的时候填入这些存在结果信息。而查询内网ip地址的过程,可以成为RTNetLink。

在Linux中有一个常用的命令 ifconfig 也可以实现类似增加一个内网ip地址的功能:

比如说为网卡eth0增加一个IPV6的地址。而这个过程实际上就是调用了devinet内核模块设定好的添加新ip地址方式,并在回调中把该ip地址刷新到内存中。

注意 devinet 和 RTNetLink 严格来说不是一个存在同一个模块。虽然都是使用 rtnl_register 注册方法到rtnl模块中:

文件:/ net / ipv4 / devinet.c

文件:/ net / ipv4 / route.c

实际上整个route模块,是跟着ipv4 内核模块一起初始化好的。能看到其中就根据不同的rtnl操作符号注册了对应不同的方法。

整个DDNS的工作流程大体如下:

当然,在tcp三次握手执行之前,需要得到当前的源地址,那么就需要通过rtnl进行查询内存中分配的ip。

文件:/ include / net / route.h

这个方法核心就是 __ip_route_output_key .当目的地址或者源地址有其一为空,则会调用 __ip_route_output_key 填充ip地址。目的地址为空说明可能是在回环链路中通信,如果源地址为空,那个说明可能往目的地址通信需要填充本地被DDNS分配好的内网地址。

在这个方法中核心还是调用了 flowi4_init_output 进行flowi4结构体的初始化。

文件:/ include / net / flow.h

能看到这个过程把数据中的源地址,目的地址,源地址端口和目的地址端口,协议类型等数据给记录下来,之后内网ip地址的查询与更新就会频繁的和这个结构体进行交互。

能看到实际上 flowi4 是一个用于承载数据的临时结构体,包含了本次路由操作需要的数据。

执行的事务如下:

想要弄清楚ip路由表的核心逻辑,必须明白路由表的几个核心的数据结构。当然网上搜索到的和本文很可能大为不同。本文是基于LInux 内核3.1.8.之后的设计几乎都沿用这一套。

而内核将路由表进行大规模的重新设计,很大一部分的原因是网络环境日益庞大且复杂。需要全新的方式进行优化管理系统中的路由表。

下面是fib_table 路由表所涉及的数据结构:

依次从最外层的结构体介绍:

能看到路由表的存储实际上通过字典树的数据结构压缩实现的。但是和常见的字典树有点区别,这种特殊的字典树称为LC-trie 快速路由查找算法

这一篇文章对于快速路由查找算法的理解写的很不错: https://blog.csdn.net/dog250/article/details/6596046

首先理解字典树:字典树简单的来说,就是把一串数据化为二进制格式,根据左0,右1的方式构成的。

如图下所示:

这个过程用图来展示,就是沿着字典树路径不断向下读,比如依次读取abd节点就能得到00这个数字。依次读取abeh就能得到010这个数字。

说到底这种方式只是存储数据的一种方式。而使用数的好处就能很轻易的找到公共前缀,在字典树中找到公共最大子树,也就找到了公共前缀。

而LC-trie 则是在这之上做了压缩优化处理,想要理解这个算法,必须要明白在 tnode 中存在两个十分核心的数据:

这负责什么事情呢?下面就简单说说整个lc-trie的算法就能明白了。

当然先来看看方法 __ip_dev_find 是如何查找

文件:/ net / ipv4 / fib_trie.c

整个方法就是通过 tkey_extract_bits 生成tnode中对应的叶子节点所在index,从而通过 tnode_get_child_rcu 拿到tnode节点中index所对应的数组中获取叶下一级别的tnode或者叶子结点。

其中查找index最为核心方法如上,这个过程,先通过key左移动pos个位,再向右边移动(32 - bits)算法找到对应index。

在这里能对路由压缩算法有一定的理解即可,本文重点不在这里。当从路由树中找到了结果就返回 fib_result 结构体。

查询的结果最为核心的就是 fib_table 路由表,存储了真正的路由转发信息

文件:/ net / ipv4 / route.c

这个方法做的事情很简单,本质上就是想要找到这个路由的下一跳是哪里?

在这里面有一个核心的结构体名为 fib_nh_exception 。这个是指fib表中去往目的地址情况下最理想的下一跳的地址。

而这个结构体在上一个方法通过 find_exception 获得.遍历从 fib_result 获取到 fib_nh 结构体中的 nh_exceptions 链表。从这链表中找到一模一样的目的地址并返回得到的。

文件:/ net / ipv4 / tcp_output.c

❾ 利用java.nio的FileChannel能够实现按行读取文件吗(解决了)

利用java.nio的FileChannel能够实现按行读取文件:

具体思路是:设置两个缓冲区,一大一小,大的缓冲区为每次读取的量,小的缓冲区存放每行的数据(确保大小可存放文本中最长的那行)。读取的时候判断是不是换行符13,是的话则返回一行数据,不是的话继续读取,直到读完文件。

实现方法:

FileChannelfc=raf.getChannel();
//一次读取文件,读取的字节缓存数
ByteBufferfbb=ByteBuffer.allocate(1024*5);
fc.read(fbb);
fbb.flip();
//每行缓存的字节根据你的实际需求
ByteBufferbb=ByteBuffer.allocate(500);

//判断是否读完文件
publicbooleanhasNext()throwsIOException{

if(EOF)returnfalse;
if(fbb.position()==fbb.limit()){//判断当前位置是否到了缓冲区的限制
if(readByte()==0)returnfalse;
}
while(true){
if(fbb.position()==fbb.limit()){
if(readByte()==0)break;
}
bytea=fbb.get();
if(a==13){
if(fbb.position()==fbb.limit()){
if(readByte()==0)break;
}
returntrue;
}else{
if(bb.position()<bb.limit()){
bb.put(a);
}else{
if(readByte()==0)break;
}
}
}
returntrue;
}
阅读全文

与getchannel源码解析相关的资料

热点内容
卡尔曼滤波算法书籍 浏览:768
安卓手机怎么用爱思助手传文件进苹果手机上 浏览:843
安卓怎么下载60秒生存 浏览:802
外向式文件夹 浏览:235
dospdf 浏览:430
怎么修改腾讯云服务器ip 浏览:387
pdftoeps 浏览:493
为什么鸿蒙那么像安卓 浏览:735
安卓手机怎么拍自媒体视频 浏览:185
单片机各个中断的初始化 浏览:723
python怎么集合元素 浏览:480
python逐条解读 浏览:832
基于单片机的湿度控制 浏览:498
ios如何使用安卓的帐号 浏览:882
程序员公园采访 浏览:811
程序员实战教程要多长时间 浏览:974
企业数据加密技巧 浏览:134
租云服务器开发 浏览:813
程序员告白妈妈不同意 浏览:335
攻城掠地怎么查看服务器 浏览:600