-
當(dāng)前位置:首頁 > 創(chuàng)意學(xué)院 > 技術(shù) > 專題列表 > 正文
安卓tcp開發(fā)(android tcp)
大家好!今天讓創(chuàng)意嶺的小編來大家介紹下關(guān)于安卓tcp開發(fā)的問題,以下是小編對此問題的歸納整理,讓我們一起來看看吧。
開始之前先推薦一個非常厲害的Ai人工智能工具,一鍵生成原創(chuàng)文章、方案、文案、工作計劃、工作報告、論文、代碼、作文、做題和對話答疑等等
只需要輸入關(guān)鍵詞,就能返回你想要的內(nèi)容,越精準(zhǔn),寫出的就越詳細(xì),有微信小程序端、在線網(wǎng)頁版、PC客戶端
官網(wǎng):https://ai.de1919.com
本文目錄:
一、如何搭建 android 開發(fā)環(huán)境
一.認(rèn)識android的架構(gòu)
Android其本質(zhì)就是在標(biāo)準(zhǔn)的Linux系統(tǒng)上增加了Java虛擬機(jī)Dalvik,并在Dalvik虛擬機(jī)上搭建了一個JAVA的application framework,所有的應(yīng)用程序都是基于JAVA的application framework之上。
android分為四個層,從高層到低層分別是應(yīng)用程序?qū)?、?yīng)用程序框架層、系統(tǒng)運(yùn)行庫層和linux核心層。
二.搭建環(huán)境
搭建開發(fā)環(huán)境
對國內(nèi)的開發(fā)者來說最痛苦的是無法去訪問android開發(fā)網(wǎng)站。為了更好的認(rèn)識世界,對程序員來說,會翻墻也是的一門技術(shù),帶你去領(lǐng)略墻外的世界,好了,不廢話了, 國內(nèi)開發(fā)者訪問(androiddevtools) 上面已經(jīng)有了所有你要的資源,同時可以下載到我們的主角framework
但是這樣的搭建只能去閱讀源代碼,我們無法去更進(jìn)一步去實現(xiàn)自己的rom,我們看到錘子的系統(tǒng)在早期的開放rom是自己從新實現(xiàn)了framework的代碼,現(xiàn)在看起來他成功了,所以我們還要去搭建android系統(tǒng)的源碼編譯環(huán)境。
搭建源碼編譯環(huán)境
三.開始主題
在一開始寫c程序的時候都有一個運(yùn)行的入口,比如
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
//這里的main就是應(yīng)用的入口
int main(int argc, const char * argv[]){
return 0;
}
在計算機(jī)網(wǎng)絡(luò)原理中我們用socket實現(xiàn)一個服務(wù)器端,不斷的接聽客戶端的訪問,而且他的代碼是這樣實現(xiàn)的:
#include <winsock2.h>
#pragma comment(lib, "WS2_32.lib")
#include <stdio.h>
void main()
{
WORD wVersionRequested;//版本號
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);//2.2版本的套接字
//加載套接字庫,如果失敗返回
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
return;
}
//判斷高低字節(jié)是不是2,如果不是2.2的版本則退出
if (LOBYTE(wsaData.wVersion) != 2 ||
HIBYTE(wsaData.wVersion) != 2)
{
return;
}
//創(chuàng)建流式套接字,基于TCP(SOCK_STREAM)
SOCKET socSrv = socket(AF_INET, SOCK_STREAM, 0);
//Socket地址結(jié)構(gòu)體的創(chuàng)建
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//轉(zhuǎn)換Unsigned long型為網(wǎng)絡(luò)字節(jié)序格
addrSrv.sin_family = AF_INET;//指定地址簇
addrSrv.sin_port = htons(6000);
//指定端口號,除sin_family參數(shù)外,其它參數(shù)都是網(wǎng)絡(luò)字節(jié)序,因此需要轉(zhuǎn)換
//將套接字綁定到一個端口號和本地地址上
bind(socSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));//必須用sizeof,strlen不行
listen(socSrv, 5);
SOCKADDR_IN addrClient;//字義用來接收客戶端Socket的結(jié)構(gòu)體
int len = sizeof(SOCKADDR);//初始化參數(shù),這個參數(shù)必須進(jìn)行初始化,sizeof
//循環(huán)等待接受客戶端發(fā)送請求
while (1)
{
//等待客戶請求到來;當(dāng)請求到來后,接受連接請求,
//返回一個新的對應(yīng)于此次連接的套接字(accept)。
//此時程序在此發(fā)生阻塞
SOCKET sockConn = accept(socSrv, (SOCKADDR*)&addrClient, &len);
char sendBuf[100];
sprintf(sendBuf, "Welcome %s to JoyChou",
inet_ntoa(addrClient.sin_addr));//格式化輸出
//用返回的套接字和客戶端進(jìn)行通信
send(sockConn, sendBuf, strlen(sendBuf)+1, 0);//多發(fā)送一個字節(jié)
//接收數(shù)據(jù)
char recvBuf[100];
recv(sockConn, recvBuf, 100, 0);
printf("%s\\n", recvBuf);
closesocket(sockConn);
}
}
他采用了一個while死循環(huán)去監(jiān)聽客戶端的請求。
先上源代碼
public final class ActivityThread {
public static void main(String[] args) {
SamplingProfilerIntegration.start();
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
EventLogger.setReporter(new EventLoggingReporter());
Security.addProvider(new AndroidKeyStoreProvider());
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
//從中可以看到為app開辟了一個線程進(jìn)入了looper之中
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
}
看到源碼失望了,沒有一個while循環(huán)啊,其實用了他方法實現(xiàn)
//用一個looper的機(jī)制循環(huán)監(jiān)聽響應(yīng)
Looper.prepareMainLooper();
Looper.loop();
進(jìn)一步深入代碼
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// 在這里看到了一個循環(huán)監(jiān)聽消息
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
二、多數(shù)安卓app和ios app服務(wù)器是tcp還是http-C/C++
看需求,主要是看連接時長。如果是一次性服務(wù),總是由Client發(fā)起的,像數(shù)據(jù)查詢/報表填交之類的,httpServer就行。如果需要即時交互的,用TCP,能雙通信。
現(xiàn)在做即時性要求不高的像webServer之類的,不用C/C++,被Java的Apacha,Python的Django/Flask/webpy還有其他開發(fā)快的各種語言大小框架取而代之。
socket的高通信量/即時性,對性能有要求,高端還是C/C++在做,小型的隨意。
三、安卓app服務(wù)器端開發(fā)用什么java架構(gòu)
首先,App的服務(wù)端跟Web的服務(wù)端沒有多大區(qū)別,而且在實際的開發(fā)過程中,業(yè)務(wù)邏輯也都是共用一套,只是會針對不同的客戶端做不同的適配(這點可參考Amazon,其對PC的web端,移動的Web端,移動的App都做了不同程度的適配).
其次,既然與Web的服務(wù)端沒多大區(qū)別,那所用的技術(shù)也大同小異,對于App而言,服務(wù)端更多是一個數(shù)據(jù)接口,所以框架頁大同小異;
最后,大致總結(jié)一下:
技術(shù):
網(wǎng)絡(luò)通信: tcp,http等;
Web服務(wù):servlet, cgi腳本,asp等;
系統(tǒng)調(diào)度:多線程,并發(fā)等;
框架:
對應(yīng)不同的web服務(wù)技術(shù),采用的編程語言不同;
對應(yīng)不同的網(wǎng)絡(luò)通信協(xié)議,采用的框架也不同,netty->tcp,servlet等web服務(wù)框架->http等;
對應(yīng)系統(tǒng)調(diào)度,有不同的多線程,多進(jìn)程通信框架等;
對應(yīng)提供不同的服務(wù)接口,有web service和restful兩大類,前者基于soap協(xié)議,后者基于http協(xié)議,對應(yīng)的框架就很多,不一一敘述;
除此之外,還有很多其他的技術(shù),可先做,發(fā)現(xiàn)問題,自然就知道怎么去找相應(yīng)的技術(shù)、解決方案(包含框架)來解決,所以先動手吧;
四、android上的socket通信的開源框架有哪些
請去360手機(jī)助手下載android學(xué)習(xí)手冊里面有例子、源碼和文檔
Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 組織一個較新的項目,它為開發(fā)高性能和高可用性的網(wǎng)絡(luò)應(yīng)用程序提供了非常便利的框架。當(dāng)前發(fā)行的 MINA 版本支持基于 Java NIO 技術(shù)的 TCP/UDP 應(yīng)用程序開發(fā)、串口通訊程序(只在最新的預(yù)覽版中提供),MINA 所支持的功能也在進(jìn)一步的擴(kuò)展中。目前正在使用 MINA 的軟件包括有:Apache Directory Project、AsyncWeb、AMQP(Advanced Message Queuing Protocol)、RED5 Server(Macromedia Flash Media RTMP)、ObjectRADIUS、Openfire 等等。
以上是從網(wǎng)上找到的mina框架簡單介紹。
由于正在開發(fā)的項目中要求加入及時通信功能(游戲方面),所以在網(wǎng)上找了好幾種框架,像openfire、tigase等都是基于Xmpp協(xié)議開發(fā)的優(yōu)秀框架。但這些側(cè)重于消息的推送,不適合游戲上的簡單交互。所以后來找到了mina這個框架,順手搭建起來。接下來就是這幾天學(xué)習(xí)的總結(jié)了,文章里面沒有涉及到邏輯層的方面,只是簡單的實現(xiàn)即時通信功能。資源下載我會放在文章的最后面。
一、相關(guān)資源下載
(1)Apache官方網(wǎng)站:http://mina.apache.org/downloads.html
(2) Android用jar包(包括官網(wǎng)的資源,我會一律放在百度網(wǎng)盤下)
二、Mina簡單配置
服務(wù)器端一共要用到四個jar包,包括一個日志包。將他們放在lib中,并加載進(jìn)去
分別為 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,添加內(nèi)容如下:
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服務(wù)端
我這邊使用的是mina2.0版本,所以可能與mina1.0的版本有所不同。那么首先在服務(wù)器端創(chuàng)建開始
新建一個Demo1Server.class文件,里面包含著程序的入口,端口號,Acceptor連接.
1 public class Demo1Server {
2 //日志類的實現(xiàn)
3 private static Logger logger = Logger.getLogger(Demo1Server.class);
4 //端口號,要求客戶端與服務(wù)器端一致
5 private static int PORT = 4444;
6
7 public static void main(String[] args){
8 IoAcceptor acceptor = null;
9 try{
10 //創(chuàng)建一個非阻塞的server端的Socket
11 acceptor = new NioSocketAcceptor();
12 //設(shè)置過濾器(使用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 //設(shè)置讀取數(shù)據(jù)的換從區(qū)大小
17 acceptor.getSessionConfig().setReadBufferSize(2048);
18 //讀寫通道10秒內(nèi)無操作進(jìn)入空閑狀態(tài)
19 acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
20 //為接收器設(shè)置管理服務(wù)
21 acceptor.setHandler(new Demo1ServerHandler());
22 //綁定端口
23 acceptor.bind(new InetSocketAddress(PORT));
24
25 logger.info("服務(wù)器啟動成功... 端口號未:"+PORT);
26
27 }catch(Exception e){
28 logger.error("服務(wù)器啟動異常...",e);
29 e.printStackTrace();
30 }
31 }
32
33 }
一個很簡單的程序入口吧,簡單的說就是在服務(wù)器上設(shè)置一個消息接收器,讓它監(jiān)聽從端口傳過來的消息并進(jìn)行處理。那么接下來我們看看怎么進(jìn)行消息處理。
新建一個消息處理類,或者說是是業(yè)務(wù)邏輯處理器——Demo1ServerHandler,它繼承了IoHandlerAdapter類,它默認(rèn)覆蓋了七個方法,而我們主要使用messageReceived()。
public class Demo1ServerHandler extends IoHandlerAdapter {
public static Logger logger = Logger.getLogger(Demo1ServerHandler.class);
//從端口接受消息,會響應(yīng)此方法來對消息進(jìn)行處理
@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
String msg = message.toString();
if("exit".equals(msg)){
//如果客戶端發(fā)來exit,則關(guān)閉該連接
session.close(true);
}
//向客戶端發(fā)送消息
Date date = new Date();
session.write(date);
logger.info("服務(wù)器接受消息成功...");
super.messageReceived(session, message);
}
//向客服端發(fā)送消息后會調(diào)用此方法
@Override
public void messageSent(IoSession session, Object message) throws Exception {
logger.info("服務(wù)器發(fā)送消息成功...");
super.messageSent(session, message);
}
//關(guān)閉與客戶端的連接時會調(diào)用此方法
@Override
public void sessionClosed(IoSession session) throws Exception {
logger.info("服務(wù)器與客戶端斷開連接...");
super.sessionClosed(session);
}
//服務(wù)器與客戶端創(chuàng)建連接
@Override
public void sessionCreated(IoSession session) throws Exception {
logger.info("服務(wù)器與客戶端創(chuàng)建連接...");
super.sessionCreated(session);
}
//服務(wù)器與客戶端連接打開
@Override
public void sessionOpened(IoSession session) throws Exception {
logger.info("服務(wù)器與客戶端連接打開...");
super.sessionOpened(session);
}
@Override
public void sessionIdle(IoSession session, IdleStatus status)
throws Exception {
logger.info("服務(wù)器進(jìn)入空閑狀態(tài)...");
super.sessionIdle(session, status);
}
@Override
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
logger.info("服務(wù)器發(fā)送異常...");
super.exceptionCaught(session, cause);
}
}
很直白的一段程序,相當(dāng)于將服務(wù)器分成了七個狀態(tài),而每個狀態(tài)都有自己的一套邏輯處理方案。
至此,一個最簡單的Mina服務(wù)器框架就搭好了,我們可以使用電腦上的telnet命令來測試一下服務(wù)器能否使用
cmd控制臺—>telnet <ip地址> <端口號> 如我的服務(wù)器ip地為192.168.1.10 那我就寫telnet 192.168.1.10 4444 .此時我們可以看到輸出日志為
此時連接已經(jīng)創(chuàng)建,我們在輸入信息服務(wù)器就會對信息進(jìn)行處理,并給出相應(yīng)的應(yīng)答。
(telnet的用法不知道的可以自行百度)
三、Mina客戶端(Android端)
服務(wù)器簡單搭建完畢,那么開始在Android端是配置服務(wù)器吧。同樣的不要忘記加載jar包, 由于Android自帶了Logout,所以就不使用Mina的日志包了。
由于接受消息會阻塞Android的進(jìn)程,所以我把它開在子線程中(同時將其放在Service中,讓其在后臺運(yùn)行)
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 //設(shè)置鏈接超時時間
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));//創(chuàng)建鏈接
19 future.awaitUninterruptibly();// 等待連接創(chuàng)建完成
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 }
不知道你們注意到了沒,客戶端的代碼與服務(wù)器端的極其相似,不同的是服務(wù)器是創(chuàng)建NioSocketAcceptor對象,而客戶端是創(chuàng)建NioSocketConnect對象。當(dāng)然同樣需要添加編碼解碼過濾器和業(yè)務(wù)邏輯過濾器。
業(yè)務(wù)邏輯過濾器代碼:
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","客戶端發(fā)生異常");
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 }
方法功能與服務(wù)器端一樣。測試這里就不做了??梢缘脑捵约簩憘€Demo效果更好
四、Mina的更多功能
拿到所有客戶端Session
Collection<IoSession> sessions = session.getService().getManagedSessions().values();
自定義編碼解碼器,可以對消息進(jìn)行預(yù)處理。要繼承ProtocolEncoder和ProtocolDecode類。
數(shù)據(jù)對象的傳遞
這些功能不便放在這里講了,可能我會以后再找機(jī)會另開一篇來講述這些功能~,大家可以瀏覽結(jié)尾處的參考文章來加深對mina的理解。
在我認(rèn)為,熟悉和快速使用一個新的的框架可以看出一個程序員的水平,同樣及時總結(jié)和歸納自己學(xué)到的新知識也是一個好的程序員該具有的習(xí)慣。那么Mina的簡單搭建就到這里為止了,希望對大家有所幫助
以上就是關(guān)于安卓tcp開發(fā)相關(guān)問題的回答。希望能幫到你,如有更多相關(guān)問題,您也可以聯(lián)系我們的客服進(jìn)行咨詢,客服也會為您講解更多精彩的知識和內(nèi)容。
推薦閱讀:
手機(jī)房屋3d設(shè)計軟件(手機(jī)房屋3d設(shè)計軟件安卓下載)
安卓手機(jī)怎么打開油管(安卓手機(jī)怎么打開油管視頻)
上海綠化景觀設(shè)計說明(上海園林綠化景觀設(shè)計)