LocalServerSocket是屬於Android系統內置的一個類,屬於net包下,類似java中的serversocket類的功能。
這個類比較簡單,構造方法有兩個:
一般使用第一個即可;
本類中方法只有四個,分別是:
查看LocalServerSocket源碼可知:
本類內容比較簡單,主要實現方式都在LocalSocketImpl中,下次分析。
內容基本同LocalScoket,主要功能也是通過LocalSocketImpl實現的。
⑵ 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的簡單搭建就到這里為止了,希望對大家有所幫助
⑶ Android-Socket
由於二者不屬於同一層面,所以本來是沒有可比性的。但隨著發展,默認的Http里封裝了下面幾層的使用,所以才會出現Socket & HTTP協議的對比:(主要是工作方式的不同):
Socket可理解為一種特殊的文件,在伺服器和客戶端各自維護一個文件,並使用SocketAPI函數對其進行文件操作。在建立連接打開後,可以向各自文件寫入內容供對方讀取或讀取對方內容,通信結束時關閉文件。在UNIX哲學中「一切皆文件」,文件的操作模式基本為「打開-讀寫-關閉」三大步驟,Socket其實就是這個模式的一個實現。
創建socket的時候,也可以指定不同的參數創建不同的socket描述符,socket函數的三個參數分別為:
當我們調用socket創建一個socket時,返回的socket描述字它存在於協議族(address family,AF_XXX)空間中,但沒有一個具體的地址。如果想要給它賦值一個地址,就必須調用bind()函數,否則就當調用connect()、listen()時系統會自動隨機分配一個埠。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
函數的三個參數分別為:
如果作為一個伺服器,在調用socket()、bind()之後就會調用listen()來監聽這個socket,如果客戶端這時調用connect()發出連接請求,伺服器端就會接收到這個請求。
TCP伺服器端依次調用socket()、bind()、listen()之後,就會監聽指定的socket地址了。TCP客戶端依次調用socket()、connect()之後就想TCP伺服器發送了一個連接請求。TCP伺服器監聽到這個請求之後,就會調用accept()函數取接收請求,這樣連接就建立好了。之後就可以開始網路I/O操作了,即類同於普通文件的讀寫I/O操作。
注意:accept的第一個參數為伺服器的socket描述字,是伺服器開始調用socket()函數生成的,稱為監聽socket描述字;而accept函數返回的是已連接的socket描述字。一個伺服器通常通常僅僅只創建一個監聽socket描述字,它在該伺服器的生命周期內一直存在。內核為每個由伺服器進程接受的客戶連接創建了一個已連接socket描述字,當伺服器完成了對某個客戶的服務,相應的已連接socket描述字就被關閉。
萬事具備只欠東風,至此伺服器與客戶已經建立好連接了。可以調用網路I/O進行讀寫操作了,即實現了網咯中不同進程之間的通信!網路I/O操作有下面幾組:
read()/write()
recv()/send()
readv()/writev()
recvmsg()/sendmsg()
recvfrom()/sendto()
我推薦使用recvmsg()/sendmsg()函數,這兩個函數是最通用的I/O函數,實際上可以把上面的其它函數都替換成這兩個函數。
從圖中可以看出,當客戶端調用connect時,觸發了連接請求,向伺服器發送了SYN J包,這時connect進入阻塞狀態;伺服器監聽到連接請求,即收到SYN J包,調用accept函數接收請求向客戶端發送SYN K ,ACK J+1,這時accept進入阻塞狀態;客戶端收到伺服器的SYN K ,ACK J+1之後,這時connect返回,並對SYN K進行確認;伺服器收到ACK K+1時,accept返回,至此三次握手完畢,連接建立。
總結:客戶端的connect在三次握手的第二個次返回,而伺服器端的accept在三次握手的第三次返回。
某個應用進程首先調用close主動關閉連接,這時TCP發送一個FIN M;
另一端接收到FIN M之後,執行被動關閉,對這個FIN進行確認。它的接收也作為文件結束符傳遞給應用進程,因為FIN的接收意味著應用進程在相應的連接上再也接收不到額外數據;
一段時間之後,接收到文件結束符的應用進程調用close關閉它的socket。這導致它的TCP也發送一個FIN N;
接收到這個FIN的源發送端TCP對它進行確認。
這樣每個方向上都有一個FIN和ACK。
所謂短連接,即連接只保持在數據傳輸過程,請求發起,連接建立,數據返回,連接關閉。它適用於一些實時數據請求,配合輪詢來進行新舊數據的更替。
https://github.com/nuisanceless/MySocketDemo
https://github.com/xuuhaoo/OkSocket
⑷ 在android如何開發socket應用
Socket和java的模式一樣都是Socket socket = new Socket(ip, port);socket.getInputStream()和socket.getOutputStream()接收或發送數據
⑸ Android如何進行socket通信
很簡單的可以做成這樣,非主要代碼就忽略了在這里:
客戶端:
newThread(){
publicvoidrun(){
try{
SocketmSocket=newSocket("192.168.1.102",2013);
while(true){
mSocket.getOutputStream.write("Helloserver!imandroidclient!");
Thread.sleep(1000);//休眠1S
}
}catch(Exceptione){}
}
}
伺服器端:
new Thread() {
public void run(){
try{
ServerSocket mSocket = new ServerSocket(2013);
while(true){
String hello = new DataInputStream(mSocket.getInputStream()).readUTF();
Log.d("Debug", hello);
Thread.sleep(1000); // 休眠1S
}
} catch(Exception e){}
}
}
最簡單的就是這樣了,你還想多復雜???
⑹ 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
⑺ Android 基於UDP的Socket通信
1、連接DatagramSocket的服務端(ip和port):開啟非同步線程和socket
2、發送數據(DatagramPacket):非同步
3、接收數據(DatagramPacket):注意連接狀態,非同步讀取
4、關閉連接:關閉DatagramSocket和對應線程
1、異常:android.os.NetworkOnMainThreadException。 socket需要在線程中使用
2、前後端統一傳輸或者接收協議 [requestcode size d1 d2 d3 ... ],在解析時候用得到
3、實施監控socket的連接狀態,還是用心跳包發過去,然後返回數據,一段時間沒有的話則代表socket連接失敗。
4、注意receive接收數據後的有效長度(一個是預存的buffer,一個是有效結果buffer)
5、客戶端連上去後不知道為何一定要先發送一次,才能接收?
6、UDP不安全,有長度限制64K
2019 (* ̄(oo) ̄) 諸事順利!
⑻ Android如何進行Socket通信
舉一個簡單的例子吧。
伺服器端:
importjava.io.IOException;
importjava.io.OutputStream;
importjava.net.ServerSocket;
importjava.net.Socket;
/**
*簡單Socket伺服器類
*/
publicclassSimpleServer{
publicstaticvoidmain(String[]args)throwsIOException{
//創建Socket伺服器,監聽客戶端Socket的連接請求
ServerSocketserver=newServerSocket(30000);
while(true){
//每當接收到客戶端Socket請求,Socket伺服器端會產生一個對應的Socket
Socketclient=server.accept();
OutputStreamos=client.getOutputStream();
os.write("歡迎您連接伺服器".getBytes("utf-8"));
os.close();
client.close();
}
}
}
Android客戶端:
packagecom.simpleclient;
importjava.io.BufferedReader;
importjava.io.InputStream;
importjava.io.InputStreamReader;
importjava.net.Socket;
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.widget.TextView;
{
TextViewtextView;
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView=(TextView)findViewById(R.id.textView1);
MyThreadthread=newMyThread();
thread.start();
}
/**
*線程類
*/
classMyThreadextendsThread{
publicvoidrun(){
try{
Socketsocket=newSocket("192.168.1.51",30000);
InputStreamis=socket.getInputStream();
InputStreamReaderisr=newInputStreamReader(is);
BufferedReaderbr=newBufferedReader(isr);
textView.setText(br.readLine());
br.close();
isr.close();
is.close();
socket.close();
}
catch(Exceptione){
System.out.println(e.toString());
}
}
}
}
修改AndroidManifest.xml文件,允許訪問Internet:
<!--添加網路訪問許可權-->
<uses-permissionandroid:name="android.permission.INTERNET"/>
⑼ android socket有幾種方法
/***第一種:客戶端Socket通過構造方法連接伺服器***/
//客戶端Socket可以通過指定IP地址或域名兩種方式來連接伺服器端,實際最終都是通過IP地址來連接伺服器
//新建一個Socket,指定其IP地址及埠號
Socket socket = new Socket("192.168.0.7",80);
/***Socket 客戶端 一些常用設置***/
//客戶端socket在接收數據時,有兩種超時:1.連接伺服器超時,即連接超時;2.連接伺服器成功後,接收伺服器數據超時,即接收超時
//*設置socket 讀取數據流的超時時間
socket.setSoTimeout(5000);
//發送數據包,默認為false,即客戶端發送數據採用Nagle演算法;
//但是對於實時交互性高的程序,建議其改為true,即關閉Nagle演算法,客戶端每發送一次數據,無論數據包大小都會將這些數據發送出去
socket.setTcpNoDelay(true);
//設置客戶端socket關閉時,close()方法起作用時延遲1分鍾關閉,如果1分鍾內盡量將未發送的數據包發送出去
socket.setSoLinger(true, 60);
//設置輸出流的發送緩沖區大小,默認是8KB,即8096位元組
socket.setSendBufferSize(8096);
//設置輸入流的接收緩沖區大小,默認是8KB,即8096位元組
socket.setReceiveBufferSize(8096);
//作用:每隔一段時間檢查伺服器是否處於活動狀態,如果伺服器端長時間沒響應,自動關閉客戶端socket
//防止伺服器端無效時,客戶端長時間處於連接狀態
socket.setKeepAlive(true);
/*** Socket客戶端向伺服器端發送數據 ****/
//客戶端向伺服器端發送數據,獲取客戶端向伺服器端輸出流
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
//代表可以立即向伺服器端發送單位元組數據
socket.setOOBInline(true);
//數據不經過輸出緩沖區,立即發送
socket.sendUrgentData(65);//"A"
//向伺服器端寫數據,寫入一個緩沖區
//註:此處字元串最後必須包含「\r\n\r\n」,告訴伺服器HTTP頭已經結束,可以處理數據,否則會造成下面的讀取數據出現阻塞
//在write()方法中可以定義規則,與後台匹配來識別相應的功能,例如登錄Login()方法,可以寫為write("Login|test,123 \r\n\r\n"),供後台識別;
bw.write("Login|test,123 \r\n\r\n");
//發送緩沖區中數據,必須有
bw.flush();
/*** Socket客戶端讀取伺服器端響應數據 ****/
//socket.isConnected代表是否連接成功過
if((socket.isConnected() == true) && (socket.isClosed() == false)){//判斷Socket是否處於連接狀態
//客戶端接收伺服器端的響應,讀取伺服器端向客戶端的輸入流
InputStream is = socket.getInputStream();
//緩沖區
byte[] buffer = new byte[is.available()];
//讀取緩沖區
is.read(buffer);
//轉換為字元串
String responseInfo = new String(buffer);
//日誌中輸出
Log.i("TEST", responseInfo);
} //關閉網路
socket.close();
/***第二種:通過connect方法連接伺服器***/
Socket socket_other = new Socket();
//使用默認的連接超時
socket_other.connect(new InetSocketAddress("192.168.0.7",80));
//連接超時2s
socket_other.connect(new InetSocketAddress("192.168.0.7",80),2000);
//關閉socket
socket_other.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
⑽ android做IM 有沒有合適的socket框架
1、可以使用openfire,以前做項目用過,必要時可以修改源碼滿足需求。
2、現在做IM第三方的API有很多。如環信,極推等。
3、Socket socket = new Socket();
socket .connect(new InetSocketAddress(host, port), 20000);
socket .setSoTimeout(45000);
byte[] byte = date;//你要傳輸的數據
BufferedInputStream is = new BufferedInputStream(socket.getInputStream(), 512);
DataInputStream dis = new DataInputStream(is);
out = new BufferedOutputStream(socket.getOutputStream());
out.write(bytes);
服務端寫個socketServer監聽客戶端的請求就可以了