導航:首頁 > 操作系統 > androidsocket非阻塞

androidsocket非阻塞

發布時間:2022-08-08 00:07:11

A. socket阻塞和非阻塞的區別

阻塞socket和非阻塞socket的區別:
1、讀操作
對於阻塞的socket,當socket的接收緩沖區中沒有數據時,read調用會一直阻塞住,直到有數據到來才返回。當socket緩沖區中的數據量小於期望讀取的數據量時,返回實際讀取的位元組數。當sockt的接收緩沖區中的數據大於期望讀取的位元組數時,讀取期望讀取的位元組數,返回實際讀取的長度。
對於非阻塞socket而言,socket的接收緩沖區中有沒有數據,read調用都會立刻返回。接收緩沖區中有數據時,與阻塞socket有數據的情況是一樣的,如果接收緩沖區中沒有數據,則返回錯誤號為EWOULDBLOCK,表示該操作本來應該阻塞的,但是由於本socket為非阻塞的socket,因此立刻返回,遇到這樣的情況,可以在下次接著去嘗試讀取。如果返回值是其它負值,則表明讀取錯誤。
2、寫操作
對於寫操作write,原理是類似的,非阻塞socket在發送緩沖區沒有空間時會直接返回錯誤號EWOULDBLOCK,表示沒有空間可寫數據,如果錯誤號是別的值,則表明發送失敗。如果發送緩沖區中有足夠空間或者是不足以拷貝所有待發送數據的空間的話,則拷貝前面N個能夠容納的數據,返回實際拷貝的位元組數。
而對於阻塞Socket而言,如果發送緩沖區沒有空間或者空間不足的話,write操作會直接阻塞住,如果有足夠空間,則拷貝所有數據到發送緩沖區,然後返回.
3、建立連接
阻塞方式下,connect首先發送SYN請求道伺服器,當客戶端收到伺服器返回的SYN的確認時,則connect返回.否則的話一直阻塞.
非阻塞方式,connect將啟用TCP協議的三次握手,但是connect函數並不等待連接建立好才返回,而是立即返回。返回的錯誤碼為EINPROGRESS,表示正在進行某種過程.

4、接收
連接
對於阻塞方式的傾聽socket,accept在連接隊列中沒有建立好的連接時將阻塞,直到有可用的連接,才返回。

非阻塞傾聽socket,在有沒有連接時都立即返回,沒有連接時,返回的錯誤碼為EWOULDBLOCK,表示本來應該阻塞

B. 使用非阻塞send 0位元組的方法無法判斷socket連接.該怎麼處理

msdn所說的,並沒有什麼問題。
現在.net提供的socket類功能比較大,它包含了TcpListener和TcpClient這兩個類的功能。

你可以拆開來理解,
伺服器先用TcpListener監聽網路埠,遇到新的請求創建新的Socket對象進行通信;
客戶端用TcpClient連接遠程伺服器,然後在此基礎上用Socket對象進行通信。

所以如果你只用socket一個類來完成,顯得有些混淆,但是效果是一樣的,即有個socket對象要起到TcpListener或者TcpClient對象的作用。

C. android的socket怎樣判斷斷線

非阻塞模式,如果暫時沒有數據,返回的值也會是<=0的,如果用阻塞模式的話,返回<=0的值是可以認為socket已經無效了。

當使用 select()函數測試一個socket是否可讀時,如果select()函數返回值為1,
且使用recv()函數讀取的數據長度為0 時,就說明該socket已經斷開。

經過代碼試驗,如果進程受到一些信號時,例如:EINTR,recv()返回值小於等於0時,這是就需要判斷 errno是否等於 EINTR , 如果errno == EINTR 則說明recv函數是由於程序接收到信號後返回的,socket連接還是正常的,不應close掉socket連接。

如果write,我覺得還有一些情況需要考慮,那就是寫的太快的時候,有可能buffer寫滿了,這是,errno是EAGAIN,可以根據實際需要,如果errno是EAGAIN的話,再寫幾次。

當然,read的時候也有類似write的情況,需要check一下errno,如果是EAGAIN或者EINTR,最好不要立刻終止操作,再嘗試一下!

這是我寫的一個代碼!int SocketConnected(int sock)
{
int res,recvlen;
char buf[20] = {'\0'};
struct timeval timeout={3,0};
fd_set rdfs;
FD_ZERO(&rdfs);
FD_SET(sock,&rdfs);

res = select(sock+1,&rdfs,NULL,NULL,&timeout);

if(res > 0){

recvlen = recv(sock,buf,sizeof(buf),0);
if(recvlen > 0){
printf("socket connected\n");
return 1;
} else if (recvlen < 0 ){
if(errno == EINTR){
printf("socket connected\n");
return 1;
}else {
printf("socket disconnected! connect again!\n");
return 0;
}
} else if (recvlen == 0){
printf("socket disconnected!connect again\n");
return 0;
}
} else if(res == 0 ){
//time out
printf("socket connected\n");
return 1;
} else if(res < 0){
if (errno == EINTR){
printf("socket connected\n");
return 1;
}else{
printf("socket disconnected ! connect again!\n");
return 0;
}
}
return 0;
}

D. socket中阻塞與非阻塞如何理解

這個問題涉及三方面,一個是阻塞本身的定義,一個是阻塞現象,一個是阻塞模式設定

阻塞,就是阻擋,禁止做某工作
當系統出現阻塞現象時,

如果設置了阻塞模式,則當前程序會等待阻塞現象消失,然後繼續做事情

如果設置了非阻塞模式,則,當前程序會馬上返回相應的錯誤,停止做事情
以上只是白話描述,細節內容還是要多讀書去理解

E. socket通信可不可以Server端設成非阻塞方式,Client端設成阻塞模式

Windows用socket設置非阻塞式 :

unsigned long ul=1;

SOCKET s=socket(AF_INET,SOCK_STREAM,0);

int ret=ioctlsocket(s, FIONBIO, (unsigned long *)&ul);//設置非阻塞模式

if(ret==SOCKET_ERROR)//設置失敗

{

}

linux用socket設置非阻塞式

int flags = fcntl(socket, F_GETFL, 0);

fcntl(socket, F_SETFL, flags | O_NONBLOCK);

用socket設置非阻塞式

int flags = fcntl(socket, F_GETFL, 0);

fcntl(socket, F_SETFL, flags | O_NONBLOCK);

非阻塞設置阻塞用

int flags = fcntl(socket, F_GETFL, 0);

fcntl(socket, F_SETFL, flags & ~O_NONBLOCK);

功能描述:根據文件描述詞操作文件特性

用:

int fcntl(int fd, int cmd);

int fcntl(int fd, int cmd, long arg);

int fcntl(int fd, int cmd, struct flock *lock);

參數:

fd:文件描述詞

cmd:操作命令

arg:供命令使用參數

lock:同

操作命令供使用

. F_DUPFD :復制文件描述詞

二. FD_CLOEXEC :設置close-on-exec標志FD_CLOEXEC位0執行execve程文件保持打反則關閉

三. F_GETFD :讀取文件描述詞標志

四. F_SETFD :設置文件描述詞標志

五. F_GETFL :讀取文件狀態標志

六. F_SETFL :設置文件狀態標志

其O_RDONLY O_WRONLY O_RDWR O_CREAT O_EXCL O_NOCTTY O_TRUNC受影響

更改標志 O_APPENDO_ASYNC O_DIRECT O_NOATIME O_NONBLOCK

七. F_GETLK, F_SETLK F_SETLKW :獲取釋放或測試記錄鎖使用參數結構體指針:

F_SETLK:指定位元組范圍獲取鎖(F_RDLCK, F_WRLCK)或者釋放鎖(F_UNLCK)與另進程鎖操作發沖突返 -1並errno設置EACCES或EAGAIN

F_SETLKW:行同F_SETLK除能獲取鎖睡眠等待外等待程接收信號立即返並errno置EINTR

F_GETLK:獲取文件鎖信息

F_UNLCK:釋放文件鎖

設置讀鎖文件必須讀式打設置寫鎖文件必須寫式打設置讀寫鎖文件必須讀寫式打

F. 如何實現一個非阻塞的socket

如果poll返回後提示某個文件句柄可以讀取數據,而你讀取到的數據長度為零,說明這個文件句柄已經被關閉了,你應該關閉該文件句柄。如果你沒有關閉該句柄,下一次調用poll時還會提示該句柄可以讀取,使進程cpu時間狂長。

G. android上的socket通信的開源框架有哪些

請去360手機助手下載android學習手冊裡面有例子、源碼和文檔

Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 組織一個較新的項目,它為開發高性能和高可用性的網路應用程序提供了非常便利的框架。當前發行的 MINA 版本支持基於 Java NIO 技術的 TCP/UDP 應用程序開發、串口通訊程序(只在最新的預覽版中提供),MINA 所支持的功能也在進一步的擴展中。目前正在使用 MINA 的軟體包括有:Apache Directory Project、AsyncWeb、AMQP(Advanced Message Queuing Protocol)、RED5 Server(Macromedia Flash Media RTMP)、ObjectRADIUS、Openfire 等等。

以上是從網上找到的mina框架簡單介紹。
由於正在開發的項目中要求加入及時通信功能(游戲方面),所以在網上找了好幾種框架,像openfire、tigase等都是基於Xmpp協議開發的優秀框架。但這些側重於消息的推送,不適合游戲上的簡單交互。所以後來找到了mina這個框架,順手搭建起來。接下來就是這幾天學習的總結了,文章裡面沒有涉及到邏輯層的方面,只是簡單的實現即時通信功能。資源下載我會放在文章的最後面。

一、相關資源下載

(1)Apache官方網站:http://mina.apache.org/downloads.html

(2) Android用jar包(包括官網的資源,我會一律放在網路網盤下)

二、Mina簡單配置

伺服器端一共要用到四個jar包,包括一個日誌包。將他們放在lib中,並載入進去
分別為mina-core-2.0.7.jar slf4j-log4j12-1.7.6.jar slf4j-api-1.7.6.jar log4j-1.2.14.jar(日誌管理包)

如果要使用日誌的jar包,則要在項目的src目錄下新建一個log4j.properties,添加內容如下:

log4j.rootCategory=INFO, stdout , R

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n

log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=D:\Tomcat 5.5\logs\qc.log
log4j.appender.R.layout=org.apache.log4j.PatternLayout
1log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n

log4j.logger.com.neusoft=DEBUG
log4j.logger.com.opensymphony.oscache=ERROR
log4j.logger.net.sf.navigator=ERROR
log4j.logger.org.apache.commons=ERROR
log4j.logger.org.apache.struts=WARN
log4j.logger.org.displaytag=ERROR
log4j.logger.org.springframework=DEBUG
log4j.logger.com.ibatis.db=WARN
log4j.logger.org.apache.velocity=FATAL

log4j.logger.com.canoo.webtest=WARN

log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN
log4j.logger.org.hibernate=DEBUG
log4j.logger.org.logicalcobwebs=WARN

log4j.rootCategory=INFO, stdout , R

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n

log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=D:\Tomcat 5.5\logs\qc.log
log4j.appender.R.layout=org.apache.log4j.PatternLayout
1log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n

log4j.logger.com.neusoft=DEBUG
log4j.logger.com.opensymphony.oscache=ERROR
log4j.logger.net.sf.navigator=ERROR
log4j.logger.org.apache.commons=ERROR
log4j.logger.org.apache.struts=WARN
log4j.logger.org.displaytag=ERROR
log4j.logger.org.springframework=DEBUG
log4j.logger.com.ibatis.db=WARN
log4j.logger.org.apache.velocity=FATAL

log4j.logger.com.canoo.webtest=WARN

log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN
log4j.logger.org.hibernate=DEBUG
log4j.logger.org.logicalcobwebs=WARN

Android客戶端要加入的jar包:mina-core-2.0.7.jar slf4j-android-1.6.1-RC1.jar兩個jar包(可能直接使用上面的jar包也會行,我沒試過~)

二、Mina服務端

我這邊使用的是mina2.0版本,所以可能與mina1.0的版本有所不同。那麼首先在伺服器端創建開始

新建一個Demo1Server.class文件,裡麵包含著程序的入口,埠號,Acceptor連接.

1 public class Demo1Server {
2 //日誌類的實現
3 private static Logger logger = Logger.getLogger(Demo1Server.class);
4 //埠號,要求客戶端與伺服器端一致
5 private static int PORT = 4444;
6
7 public static void main(String[] args){
8 IoAcceptor acceptor = null;
9 try{
10 //創建一個非阻塞的server端的Socket
11 acceptor = new NioSocketAcceptor();
12 //設置過濾器(使用mina提供的文本換行符編解碼器)
13 acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"),LineDelimiter.WINDOWS.getValue(),LineDelimiter.WINDOWS.getValue())));
14 //自定義的編解碼器
15 //acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new CharsetCodecFactory()));
16 //設置讀取數據的換從區大小
17 acceptor.getSessionConfig().setReadBufferSize(2048);
18 //讀寫通道10秒內無操作進入空閑狀態
19 acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
20 //為接收器設置管理服務
21 acceptor.setHandler(new Demo1ServerHandler());
22 //綁定埠
23 acceptor.bind(new InetSocketAddress(PORT));
24
25 logger.info("伺服器啟動成功... 埠號未:"+PORT);
26
27 }catch(Exception e){
28 logger.error("伺服器啟動異常...",e);
29 e.printStackTrace();
30 }
31 }
32
33 }

一個很簡單的程序入口吧,簡單的說就是在伺服器上設置一個消息接收器,讓它監聽從埠傳過來的消息並進行處理。那麼接下來我們看看怎麼進行消息處理。

新建一個消息處理類,或者說是是業務邏輯處理器——Demo1ServerHandler,它繼承了IoHandlerAdapter類,它默認覆蓋了七個方法,而我們主要使用messageReceived()。

public class Demo1ServerHandler extends IoHandlerAdapter {
public static Logger logger = Logger.getLogger(Demo1ServerHandler.class);

//從埠接受消息,會響應此方法來對消息進行處理
@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
String msg = message.toString();
if("exit".equals(msg)){
//如果客戶端發來exit,則關閉該連接
session.close(true);
}
//向客戶端發送消息
Date date = new Date();
session.write(date);
logger.info("伺服器接受消息成功...");
super.messageReceived(session, message);
}

//向客服端發送消息後會調用此方法
@Override
public void messageSent(IoSession session, Object message) throws Exception {
logger.info("伺服器發送消息成功...");
super.messageSent(session, message);
}

//關閉與客戶端的連接時會調用此方法
@Override
public void sessionClosed(IoSession session) throws Exception {
logger.info("伺服器與客戶端斷開連接...");
super.sessionClosed(session);
}

//伺服器與客戶端創建連接
@Override
public void sessionCreated(IoSession session) throws Exception {
logger.info("伺服器與客戶端創建連接...");
super.sessionCreated(session);
}

//伺服器與客戶端連接打開
@Override
public void sessionOpened(IoSession session) throws Exception {
logger.info("伺服器與客戶端連接打開...");
super.sessionOpened(session);
}

@Override
public void sessionIdle(IoSession session, IdleStatus status)
throws Exception {
logger.info("伺服器進入空閑狀態...");
super.sessionIdle(session, status);
}

@Override
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
logger.info("伺服器發送異常...");
super.exceptionCaught(session, cause);
}
}

很直白的一段程序,相當於將伺服器分成了七個狀態,而每個狀態都有自己的一套邏輯處理方案。

至此,一個最簡單的Mina伺服器框架就搭好了,我們可以使用電腦上的telnet命令來測試一下伺服器能否使用
cmd控制台—>telnet <ip地址> <埠號> 如我的伺服器ip地為192.168.1.10 那我就寫telnet 192.168.1.10 4444 .此時我們可以看到輸出日誌為

此時連接已經創建,我們在輸入信息伺服器就會對信息進行處理,並給出相應的應答。
(telnet的用法不知道的可以自行網路)

三、Mina客戶端(Android端)

伺服器簡單搭建完畢,那麼開始在Android端是配置伺服器吧。同樣的不要忘記載入jar包, 由於Android自帶了Logout,所以就不使用Mina的日誌包了。
由於接受消息會阻塞Android的進程,所以我把它開在子線程中(同時將其放在Service中,讓其在後台運行)

1 public class MinaThread extends Thread {
2
3 private IoSession session = null;
4
5 @Override
6 public void run() {
7 // TODO Auto-generated method stub
8 Log.d("TEST","客戶端鏈接開始...");
9 IoConnector connector = new NioSocketConnector();
10 //設置鏈接超時時間
11 connector.setConnectTimeoutMillis(30000);
12 //添加過濾器
13 //connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new CharsetCodecFactory()));
14 connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"),LineDelimiter.WINDOWS.getValue(),LineDelimiter.WINDOWS.getValue())));
15 connector.setHandler(new MinaClientHandler(minaService));
16
17 try{
18 ConnectFuture future = connector.connect(new InetSocketAddress(ConstantUtil.WEB_MATCH_PATH,ConstantUtil.WEB_MATCH_PORT));//創建鏈接
19 future.awaitUninterruptibly();// 等待連接創建完成
20 session = future.getSession();//獲得session
21 session.write("start");
22 }catch (Exception e){
23 Log.d("TEST","客戶端鏈接異常...");
24 }
25 session.getCloseFuture().awaitUninterruptibly();//等待連接斷開
26 Log.d("TEST","客戶端斷開...");
27 connector.dispose();
28 super.run();
29 }
30
31 }

不知道你們注意到了沒,客戶端的代碼與伺服器端的極其相似,不同的是伺服器是創建NioSocketAcceptor對象,而客戶端是創建NioSocketConnect對象。當然同樣需要添加編碼解碼過濾器和業務邏輯過濾器。

業務邏輯過濾器代碼:

1 public class MinaClientHandler extends IoHandlerAdapter{
2
3
4 @Override
5 public void exceptionCaught(IoSession session, Throwable cause)
6 throws Exception {
7 Log.d("TEST","客戶端發生異常");
8 super.exceptionCaught(session, cause);
9 }
10
11 @Override
12 public void messageReceived(IoSession session, Object message)
13 throws Exception {
14 String msg = message.toString();
15 Log.d("TEST","客戶端接收到的信息為:" + msg);
16 super.messageReceived(session, message);
17 }
18
19 @Override
20 public void messageSent(IoSession session, Object message) throws Exception {
21 // TODO Auto-generated method stub
22 super.messageSent(session, message);
23 }
24 }

方法功能與伺服器端一樣。測試這里就不做了。可以的話自己寫個Demo效果更好

四、Mina的更多功能

拿到所有客戶端Session

Collection<IoSession> sessions = session.getService().getManagedSessions().values();

自定義編碼解碼器,可以對消息進行預處理。要繼承ProtocolEncoder和ProtocolDecode類。

數據對象的傳遞

這些功能不便放在這里講了,可能我會以後再找機會另開一篇來講述這些功能~,大家可以瀏覽結尾處的參考文章來加深對mina的理解。

在我認為,熟悉和快速使用一個新的的框架可以看出一個程序員的水平,同樣及時總結和歸納自己學到的新知識也是一個好的程序員該具有的習慣。那麼Mina的簡單搭建就到這里為止了,希望對大家有所幫助

H. 如何將CSocket設置為非阻塞模式(VC)

用IOCTL可以做到。

BOOL IOCtl( long lCommand, DWORD* lpArgument );

lCommand:
FIONBIO Enable or disable nonblocking mode on the socket.

I. recv是阻塞還是非阻塞的

網路編程函數如recv是阻塞(同步)還是非阻塞(非同步)取決於在調用recv函數前創建的套接字socket是阻塞還是非阻塞。socket默認創建時設定為阻塞模式;若要將socket設定為非阻塞模式,可以在socket創建時設定為非阻塞模式,那麼函數recv就是非阻塞的。
可以通過一下幾種方法設定socket為非阻塞:
1.linux平台可以在利用socket()函數創建socket時指定socket是非同步(非阻塞)的:
int socket(int domain, int type, int protocol);
在參數type中設置SOCK_NONBLOCK標志即可,例如:
int s = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
2.windows和linux平台accept()函數返回的socekt也是阻塞的,linux另外提供了一個accept4()函數,可以直接將socket設置為非阻塞模式:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
只要將accept4()最後一個參數flags設置成SOCK_NONBLOCK即可。

3.除了在創建socket時,將socket設置為非阻塞模式,還可以通過以下函數來設置:

linux平台可以調用fcntl()或ioctl()函數,例如:
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK);
ioctl(sockfd, FIONBIO, 1); //1:非阻塞 0:阻塞
windows平台可調用ioctlsocket函數:

int ioctlsocket(
_In_ SOCKET s,
_In_ long cmd,
_Inout_ u_long *argp
);
將cmd參數設置為FIONBIO,*argp=0即設置成阻塞模式,而*argp非0即可設置成非阻塞模式。但windows平台一個地方需要注意,如果對一個socket調用了WSAAsyncSelect()或WSAEventSelect()函數後,你再調用ioctlsocket()函數將該socket設置為阻塞模式,則會失敗,必須先調用WSAAsyncSelect()設置lEvent參數為0或調用WSAEventSelect()設置lNetworkEvents參數為0來分別禁用WSAAsyncSelect()或WSAEventSelect(),再次調用ioctlsocket()將該socket設置成阻塞模式才會成功。因為調用WSAAsyncSelect()或WSAEventSelect()函數會自動將socket設置成非阻塞模式。

J. socket中recv不是阻塞的么,沒包為什麼會通過

在客戶端斷開socket連接後mysock.accept()會不停的返回0,沒有斷開連接的情況下是阻塞的...............

至於非阻塞
socket.setblocking(flag)
Set blocking or non-blocking mode of the socket: if flag is 0, the socket is set to non-blocking, else to blocking mode. Initially all sockets are in blocking mode. In non-blocking mode, if a recv() call doesn』t find any data, or if a send() call can』t immediately dispose of the data, a error exception is raised; in blocking mode, the calls block until they can proceed. s.setblocking(0) is equivalent to s.settimeout(0); s.setblocking(1) is equivalent to s.settimeout(None).

設置socket.setblocking(0)
python默認是阻塞的

閱讀全文

與androidsocket非阻塞相關的資料

熱點內容
如何用本機登陸遠程伺服器地址 瀏覽:680
黃小鴨解壓文具盒 瀏覽:670
女程序員的轉行方法 瀏覽:881
東風啟辰車聯網安裝文件夾 瀏覽:524
華為怎麼設置app時間鎖 瀏覽:660
後宮app視頻怎麼下載 瀏覽:525
如何把圖片轉換從PDF格式 瀏覽:259
重寫和重載的區別java 瀏覽:233
expressvpnandroid 瀏覽:84
儲存卡被加密怎麼解除 瀏覽:169
地球怎麼壓縮直徑 瀏覽:780
金鏟鏟之戰伺服器爆滿怎麼進 瀏覽:160
同仁堂pdf 瀏覽:935
如何編譯原理課程教材 瀏覽:730
單片機控制顯示器 瀏覽:776
頂好花app下載怎麼找不到 瀏覽:989
手機命令大全 瀏覽:808
怎麼下郵政銀行app 瀏覽:250
不背單詞app單詞怎麼學習 瀏覽:481
程序員日常操作搞笑 瀏覽:382