Socket在Android網(wǎng)絡(luò)編程中,有著非常重要的作用腔丧。
Socket基本概念
即套接字,是應(yīng)用層 與 TCP/IP 協(xié)議族通信的中間軟件抽象層作烟,表現(xiàn)為一個封裝了 TCP / IP協(xié)議族 的編程接口(API)愉粤。
從設(shè)計模式的角度看來,Socket其實就是一個門面模式拿撩,它把復(fù)雜的TCP/IP協(xié)議族隱藏在Socket接口后面衣厘,對用戶來說,一組簡單的接口就是全部压恒,讓Socket去組織數(shù)據(jù)影暴,以符合指定的協(xié)議。
借用下網(wǎng)上結(jié)構(gòu)圖:
IP地址和端口號組成了Socket涎显,都是成對出現(xiàn)坤检。
Socket ={(IP地址1:PORT端口號)兴猩,(IP地址2:PORT端口號)}
單獨(dú)的Socke是沒用任何作用的,基于一定的協(xié)議(TCP或者UDP)下的Socket編程才能進(jìn)行數(shù)據(jù)傳輸期吓。
Socket工作流程
服務(wù)端先初始化Socket,然后與端口綁定(bind)倾芝,對端口進(jìn)行監(jiān)聽(listen)讨勤,調(diào)用accept阻塞,等待客戶端連接晨另。
客戶端初始化一個socket潭千,然后連接服務(wù)器(connect),如果連接成功借尿,這時客戶端與服務(wù)端的連接就建立了刨晴。
客戶端發(fā)送數(shù)據(jù)請求,服務(wù)端接收請求并處理請求路翻,然后把回應(yīng)數(shù)據(jù)發(fā)給客戶端狈癞,客戶端讀取數(shù)據(jù),最后關(guān)閉數(shù)據(jù)茂契,一次交互結(jié)束蝶桶。
分類
Socket使用類型有兩種:
- 基于TCP協(xié)議,流套接字掉冶,采用流的方式提供可靠的字節(jié)流服務(wù)
- 基于UDP協(xié)議真竖,數(shù)據(jù)報套接字脐雪,采用數(shù)據(jù)報文提供數(shù)據(jù)打包發(fā)送的服務(wù)
基于TCP的Socket編程
主要API
Socket
構(gòu)造方法
public Socket(String host, int port)
throws UnknownHostException, IOException
創(chuàng)建流套接字并將其連接到指定主機(jī)上的指定端口號。
-
host
: 主機(jī)地址 -
port
: 端口號
getInputStream
返回Socket的輸入流恢共,用戶接受數(shù)據(jù)战秋。
getOutputStream
返回Socket的輸出流,用于發(fā)送數(shù)據(jù)讨韭。
ServerSocket
Socket的服務(wù)端實現(xiàn)
構(gòu)造函數(shù)
public ServerSocket(int port) throws IOException
創(chuàng)建服務(wù)端Socket获询,綁定到指定端口。
-
port
: 端口號
accept
public Socket accept() throws IOException
監(jiān)聽并接受到此套接字的連接拐袜。該方法將阻塞吉嚣,直到建立連接。
示例
服務(wù)端
public class Server {
public static void main(String[] args) throws IOException {
//1. 創(chuàng)建ServerSocket
ServerSocket serverSocket = new ServerSocket(8888);
//2. 監(jiān)聽
Socket socket = serverSocket.accept();
System.out.println("server start listen");
//3. 輸入流
InputStream is = socket.getInputStream();
InputStreamReader reader = new InputStreamReader(is);
BufferedReader br = new BufferedReader(reader);
String content = null;
StringBuffer sb = new StringBuffer();
while ((content = br.readLine()) != null) {
sb.append(content);
}
System.out.println("server receiver: " + sb.toString());
socket.shutdownInput();
br.close();
reader.close();
is.close();
socket.close();
serverSocket.close();
}
}
非常簡單的Socket服務(wù)端蹬铺,接收到客戶端的數(shù)據(jù)尝哆,就會關(guān)閉當(dāng)前的連接。這個示例只是展示了一個完整的流程甜攀。
如果需要復(fù)雜的服務(wù)端實現(xiàn)渗鬼,可以使用Netty、Mina或者其他Socket框架饺蚊。
客戶端
//1. 創(chuàng)建客戶端
Socket socket = new Socket("your ip", 8888);
//2. 輸出流
OutputStream os = socket.getOutputStream();
//3. 發(fā)送數(shù)據(jù)
os.write("Hello world".getBytes());
System.out.println("send message");
os.flush();
socket.shutdownOutput();
os.close();
socket.close();
客戶端就是連接后衷咽,發(fā)送了一份數(shù)據(jù),就關(guān)閉連接了谁撼。
這樣就實現(xiàn)了客戶端和服務(wù)端的通信歧胁。
基于UDP的Socket編程
主要API
DatagramPacket
用來包裝接收和發(fā)送的數(shù)據(jù)。
- 構(gòu)造接收數(shù)據(jù)包
public DatagramPacket(byte[] buf,int length)
用來接收長度為 length 的數(shù)據(jù)包厉碟。
- 構(gòu)造發(fā)送數(shù)據(jù)包
DatagramPacket(byte[] buf, int length,SocketAddress address)
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
用來將長度為 length 的包發(fā)送到指定主機(jī)上的指定端口號喊巍。
DatagramSocket
用來發(fā)送和接收數(shù)據(jù)報包的套接字。
構(gòu)造方法
//創(chuàng)建數(shù)據(jù)報套接字并將其綁定到本地主機(jī)上的指定端口
DatagramSocket(int port)
//創(chuàng)建數(shù)據(jù)報套接字箍鼓,將其綁定到指定的本地地址
DatagramSocket(int port, InetAddress laddr)
發(fā)送數(shù)據(jù)
void send(DatagramPacket p)
DatagramPacket 包含的信息指示:將要發(fā)送的數(shù)據(jù)崭参、其長度、遠(yuǎn)程主機(jī)的 IP 地址和遠(yuǎn)程主機(jī)的端口號
接收數(shù)據(jù)
void receive(DatagramPacket p)
當(dāng)此方法返回時款咖,DatagramPacket的緩沖區(qū)填充了接收的數(shù)據(jù)何暮。
示例
服務(wù)端
public class UDPServer {
public static void main(String[] args) throws IOException {
byte[] buf = new byte[1024];
// receive
// 1.create
DatagramPacket packet = new DatagramPacket(buf, buf.length);
// 2.create udp socket
DatagramSocket socket = new DatagramSocket(8888);
// 3. receive start
socket.receive(packet);
// 4. receive data
System.out.println("sever: " + new String(buf, 0, buf.length));
// send
DatagramPacket p = new DatagramPacket(buf, buf.length,
packet.getAddress(), packet.getPort());
socket.send(p);
socket.close();
}
}
客戶端
// send
InetAddress address = InetAddress.getByName("your ip");
//1.create packet
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address, 8888);
//2.create socket
DatagramSocket socket = new DatagramSocket();
//3.send data
socket.send(packet);
// receive
//1.create packet
final byte[] bytes = new byte[1024];
DatagramPacket receiverPacket = new DatagramPacket(bytes, bytes.length);
socket.receive(receiverPacket);
System.out.println("client: " + new String(bytes, 0, bytes.length));
socket.close();
客戶端和服務(wù)端的實現(xiàn),都比較簡單铐殃。
關(guān)于Socket編程海洼,就介紹好了,這篇只是開了頭背稼,最主要的還是得去項目中實踐贰军。