Android Socket通信詳解
一、Socket通信簡(jiǎn)介
Android與服務(wù)器的通信方式主要有兩種,一是Http通信,一是Socket通信。兩者的最大差異在于,http連接使用的是“請(qǐng)求—響應(yīng)方式”,即在請(qǐng)求時(shí)建立連接通道,當(dāng)客戶端向服務(wù)器發(fā)送請(qǐng)求后,服務(wù)器端才能向客戶端返回?cái)?shù)據(jù)。而Socket通信則是在雙方建立起連接后就可以直接進(jìn)行數(shù)據(jù)的傳輸,在連接時(shí)可實(shí)現(xiàn)信息的主動(dòng)推送,而不需要每次由客戶端想服務(wù)器發(fā)送請(qǐng)求。 那么,什么是socket?Socket又稱套接字,在程序內(nèi)部提供了與外界通信的端口,即端口通信。通過(guò)建立socket連接,可為通信雙方的數(shù)據(jù)傳輸傳提供通道。socket的主要特點(diǎn)有數(shù)據(jù)丟失率低,使用簡(jiǎn)單且易于移植。
1.1什么是Socket Socket
是一種抽象層,應(yīng)用程序通過(guò)它來(lái)發(fā)送和接收數(shù)據(jù),使用Socket可以將應(yīng)用程序添加到網(wǎng)絡(luò)中,與處于同一網(wǎng)絡(luò)中的其他應(yīng)用程序進(jìn)行通信。簡(jiǎn)單來(lái)說(shuō),Socket提供了程序內(nèi)部與外界通信的端口并為通信雙方的提供了數(shù)據(jù)傳輸通道。
1.2Socket的分類
根據(jù)不同的的底層協(xié)議,Socket的實(shí)現(xiàn)是多樣化的。本指南中只介紹TCP/IP協(xié)議族的內(nèi)容,在這個(gè)協(xié)議族當(dāng)中主要的Socket類型為流套接字(streamsocket)和數(shù)據(jù)報(bào)套接字(datagramsocket)。流套接字將TCP作為其端對(duì)端協(xié)議,提供了一個(gè)可信賴的字節(jié)流服務(wù)。數(shù)據(jù)報(bào)套接字使用UDP協(xié)議,提供數(shù)據(jù)打包發(fā)送服務(wù)。 下面,我們來(lái)認(rèn)識(shí)一下這兩種Socket類型的基本實(shí)現(xiàn)模型。
二、Socket 基本通信模型

三、Socket基本實(shí)現(xiàn)原理
3.1基于TCP協(xié)議的Socket
服務(wù)器端首先聲明一個(gè)ServerSocket對(duì)象并且指定端口號(hào),然后調(diào)用Serversocket的accept()方法接收客戶端的數(shù)據(jù)。accept()方法在沒(méi)有數(shù)據(jù)進(jìn)行接收的處于堵塞狀態(tài)。(Socketsocket=serversocket.accept()),一旦接收到數(shù)據(jù),通過(guò)inputstream讀取接收的數(shù)據(jù)。
客戶端創(chuàng)建一個(gè)Socket對(duì)象,指定服務(wù)器端的ip地址和端口號(hào)(Socketsocket=newSocket("172.168.10.108",8080);),通過(guò)inputstream讀取數(shù)據(jù),獲取服務(wù)器發(fā)出的數(shù)據(jù)(OutputStreamoutputstream=socket.getOutputStream()),最后將要發(fā)送的數(shù)據(jù)寫入到outputstream即可進(jìn)行TCP協(xié)議的socket數(shù)據(jù)傳輸。
3.2基于UDP協(xié)議的數(shù)據(jù)傳輸
服務(wù)器端首先創(chuàng)建一個(gè)DatagramSocket對(duì)象,并且指點(diǎn)監(jiān)聽(tīng)的端口。接下來(lái)創(chuàng)建一個(gè)空的DatagramSocket對(duì)象用于接收數(shù)據(jù)(bytedata[]=newbyte[1024;]DatagramSocketpacket=newDatagramSocket(data,data.length)),使用DatagramSocket的receive方法接收客戶端發(fā)送的數(shù)據(jù),receive()與serversocket的accepet()類似,在沒(méi)有數(shù)據(jù)進(jìn)行接收的處于堵塞狀態(tài)。
客戶端也創(chuàng)建個(gè)DatagramSocket對(duì)象,并且指點(diǎn)監(jiān)聽(tīng)的端口。接下來(lái)創(chuàng)建一個(gè)InetAddress對(duì)象,這個(gè)對(duì)象類似與一個(gè)網(wǎng)絡(luò)的發(fā)送地址(InetAddressserveraddress=InetAddress.getByName("172.168.1.120")).定義要發(fā)送的一個(gè)字符串,創(chuàng)建一個(gè)DatagramPacket對(duì)象,并制定要講這個(gè)數(shù)據(jù)報(bào)包發(fā)送到網(wǎng)絡(luò)的那個(gè)地址以及端口號(hào),最后使用DatagramSocket的對(duì)象的send()發(fā)送數(shù)據(jù)。*(Stringstr="hello";bytedata[]=str.getByte();DatagramPacketpacket=new DatagramPacket(data,data.length,serveraddress,4567);socket.send(packet);)
四、android 實(shí)現(xiàn)socket簡(jiǎn)單通信
前言:添加權(quán)限
<!--允許應(yīng)用程序改變網(wǎng)絡(luò)狀態(tài)-->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<!--允許應(yīng)用程序改變WIFI連接狀態(tài)-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<!--允許應(yīng)用程序訪問(wèn)有關(guān)的網(wǎng)絡(luò)信息-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!--允許應(yīng)用程序訪問(wèn)WIFI網(wǎng)卡的網(wǎng)絡(luò)信息-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!--允許應(yīng)用程序完全使用網(wǎng)絡(luò)-->
<uses-permission android:name="android.permission.INTERNET"/>
4.1使用TCP協(xié)議通信
android端實(shí)現(xiàn):
protected void connectServerWithTCPSocket() {
Socket socket;
try {// 創(chuàng)建一個(gè)Socket對(duì)象,并指定服務(wù)端的IP及端口號(hào)
socket = new Socket("...", );
// 創(chuàng)建一個(gè)InputStream用戶讀取要發(fā)送的文件。
InputStream inputStream = new FileInputStream("e://a.txt");
// 獲取Socket的OutputStream對(duì)象用于發(fā)送數(shù)據(jù)。
OutputStream outputStream = socket.getOutputStream();
// 創(chuàng)建一個(gè)byte類型的buffer字節(jié)數(shù)組,用于存放讀取的本地文件
byte buffer[] = new byte[ * ];
int temp = ;
// 循環(huán)讀取文件
while ((temp = inputStream.read(buffer)) != -) {
// 把數(shù)據(jù)寫入到OuputStream對(duì)象中
outputStream.write(buffer, , temp);
}
// 發(fā)送讀取的數(shù)據(jù)到服務(wù)端
outputStream.flush();
/** 或創(chuàng)建一個(gè)報(bào)文,使用BufferedWriter寫入,看你的需求 **/
// String socketData = "[;fjks;]";
// BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
// socket.getOutputStream()));
// writer.write(socketData.replace("\n", " ") + "\n");
// writer.flush();
/************************************************/
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
服務(wù)器端簡(jiǎn)單實(shí)現(xiàn):
public void ServerReceviedByTcp() {
// 聲明一個(gè)ServerSocket對(duì)象
ServerSocket serverSocket = null;
try {
// 創(chuàng)建一個(gè)ServerSocket對(duì)象,并讓這個(gè)Socket在端口監(jiān)聽(tīng)
serverSocket = new ServerSocket();
// 調(diào)用ServerSocket的accept()方法,接受客戶端所發(fā)送的請(qǐng)求,
// 如果客戶端沒(méi)有發(fā)送數(shù)據(jù),那么該線程就停滯不繼續(xù)
Socket socket = serverSocket.accept();
// 從Socket當(dāng)中得到InputStream對(duì)象
InputStream inputStream = socket.getInputStream();
byte buffer[] = new byte[ * ];
int temp = ;
// 從InputStream當(dāng)中讀取客戶端所發(fā)送的數(shù)據(jù)
while ((temp = inputStream.read(buffer)) != -) {
System.out.println(new String(buffer, , temp));
}
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
4.2使用UDP協(xié)議通信
客戶端發(fā)送數(shù)據(jù)實(shí)現(xiàn):
protected void connectServerWithUDPSocket() {
DatagramSocket socket;
try {
//創(chuàng)建DatagramSocket對(duì)象并指定一個(gè)端口號(hào),注意,如果客戶端需要接收服務(wù)器的返回?cái)?shù)據(jù),
//還需要使用這個(gè)端口號(hào)來(lái)receive,所以一定要記住
socket = new DatagramSocket();
//使用InetAddress(InetAddress).getByName把IP地址轉(zhuǎn)換為網(wǎng)絡(luò)地址
InetAddress serverAddress = InetAddress.getByName("...");
//InetAddress serverAddress = (InetAddress) InetAddress.getByName("...");
String str = "[;fjks;]";//設(shè)置要發(fā)送的報(bào)文
byte data[] = str.getBytes();//把字符串str字符串轉(zhuǎn)換為字節(jié)數(shù)組
//創(chuàng)建一個(gè)DatagramPacket對(duì)象,用于發(fā)送數(shù)據(jù)。
//參數(shù)一:要發(fā)送的數(shù)據(jù) 參數(shù)二:數(shù)據(jù)的長(zhǎng)度 參數(shù)三:服務(wù)端的網(wǎng)絡(luò)地址 參數(shù)四:服務(wù)器端端口號(hào)
DatagramPacket packet = new DatagramPacket(data, data.length ,serverAddress ,);
socket.send(packet);//把數(shù)據(jù)發(fā)送到服務(wù)端。
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
客戶端接收服務(wù)器返回的數(shù)據(jù):
public void ReceiveServerSocketData() {
DatagramSocket socket;
try {
//實(shí)例化的端口號(hào)要和發(fā)送時(shí)的socket一致,否則收不到data
socket = new DatagramSocket();
byte data[] = new byte[ * ];
//參數(shù)一:要接受的data 參數(shù)二:data的長(zhǎng)度
DatagramPacket packet = new DatagramPacket(data, data.length);
socket.receive(packet);
//把接收到的data轉(zhuǎn)換為String字符串
String result = new String(packet.getData(), packet.getOffset(),
packet.getLength());
socket.close();//不使用了記得要關(guān)閉
System.out.println("the number of reveived Socket is :" + flag
+ "udpData:" + result);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
服務(wù)器接收客戶端實(shí)現(xiàn):
public void ServerReceviedByUdp(){
//創(chuàng)建一個(gè)DatagramSocket對(duì)象,并指定監(jiān)聽(tīng)端口。(UDP使用DatagramSocket)
DatagramSocket socket;
try {
socket = new DatagramSocket();
//創(chuàng)建一個(gè)byte類型的數(shù)組,用于存放接收到得數(shù)據(jù)
byte data[] = new byte[*];
//創(chuàng)建一個(gè)DatagramPacket對(duì)象,并指定DatagramPacket對(duì)象的大小
DatagramPacket packet = new DatagramPacket(data,data.length);
//讀取接收到得數(shù)據(jù)
socket.receive(packet);
//把客戶端發(fā)送的數(shù)據(jù)轉(zhuǎn)換為字符串。
//使用三個(gè)參數(shù)的String方法。參數(shù)一:數(shù)據(jù)包 參數(shù)二:起始位置 參數(shù)三:數(shù)據(jù)包長(zhǎng)
String result = new String(packet.getData(),packet.getOffset() ,packet.getLength());
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
以上內(nèi)容是小編給大家分享的Android Socket通信詳解的相關(guān)知識(shí),希望大家喜歡。
- Android編程之客戶端通過(guò)socket與服務(wù)器通信的方法
- Android中Socket通信的實(shí)現(xiàn)方法概述
- python服務(wù)器與android客戶端socket通信實(shí)例
- android利用websocket協(xié)議與服務(wù)器通信
- Android中使用socket通信實(shí)現(xiàn)消息推送的方法詳解
- 詳解Android 基于TCP和UDP協(xié)議的Socket通信
- Android Socket通信實(shí)現(xiàn)簡(jiǎn)單聊天室
- Android中socket通信的簡(jiǎn)單實(shí)現(xiàn)
- Android開(kāi)發(fā)中Socket通信的基本實(shí)現(xiàn)方法講解
- Android Socket通信的簡(jiǎn)單實(shí)現(xiàn)
相關(guān)文章
Android studio 出現(xiàn)錯(cuò)誤Run with --stacktrace option to get the s
這篇文章主要介紹了 Android studio 出現(xiàn)錯(cuò)誤Run with --stacktrace option to get the stack trace. Run with --info or --debu的相關(guān)資料,需要的朋友可以參考下2016-11-11
Android中Android Virtual Device(AVD)使用教程
這篇文章主要介紹了Android中Android Virtual Device(AVD)使用教程,本文還對(duì)使用過(guò)程中發(fā)生的一些錯(cuò)誤給出了處理方法,需要的朋友可以參考下2015-01-01
Android實(shí)現(xiàn)手勢(shì)滑動(dòng)多點(diǎn)觸摸縮放平移圖片效果(二)
這篇文章主要介紹了Android實(shí)現(xiàn)手勢(shì)滑動(dòng)多點(diǎn)觸摸縮放平移圖片效果,實(shí)現(xiàn)圖片支持多點(diǎn)觸控,自由的進(jìn)行縮放、平移的注意事項(xiàng),感興趣的小伙伴們可以參考一下2016-02-02
Android數(shù)據(jù)類型之間相互轉(zhuǎn)換系統(tǒng)介紹
一些初學(xué)Android的朋友可能會(huì)遇到JAVA的數(shù)據(jù)類型之間轉(zhuǎn)換的苦惱;本文將為有這類需求的朋友解決此類問(wèn)題2012-11-11
Flutter移動(dòng)端進(jìn)行多渠道打包發(fā)布的全過(guò)程
在使用flutter開(kāi)發(fā)的過(guò)程中,需要根據(jù)不同的環(huán)境,不同的包名來(lái)打包,下面這篇文章主要給大家介紹了關(guān)于Flutter移動(dòng)端進(jìn)行多渠道打包發(fā)布的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06
Android網(wǎng)絡(luò)連接判斷與相關(guān)處理
這篇文章主要為大家詳細(xì)介紹了Android網(wǎng)絡(luò)連接判斷操作,幫助大家判斷WIFI網(wǎng)絡(luò)是否可用,判斷MOBILE網(wǎng)絡(luò)是否可用,感興趣的小伙伴們可以參考一下2016-08-08
Android開(kāi)發(fā)教程之shape和selector的結(jié)合使用
shape和selector是Android UI設(shè)計(jì)中經(jīng)常用到的,比如我們要自定義一個(gè)圓角Button,點(diǎn)擊Button有些效果的變化,就要用到shape和selector,接下來(lái)通過(guò)本文給大家介紹Android開(kāi)發(fā)教程之shape和selector的結(jié)合使用,感興趣的朋友一起學(xué)習(xí)吧2016-01-01
Android 自定義View之邊緣凹凸的優(yōu)惠券效果的開(kāi)發(fā)過(guò)程
這篇文章主要介紹了Android 自定義View之邊緣凹凸的優(yōu)惠券效果,主要總結(jié)一下在自定義View的開(kāi)發(fā)過(guò)程中需要注意的一些地方.需要的朋友可以參考下2018-03-03

