Socket是對TCP/IP協議的封裝,Socket本身並不是協議,而是一個針對TCP和UDP編程的接口(API),通過Socket,我們才能使用TCP/IP協議。Socket的出現只是使得程序員更方便地使用TCP/IP協議棧而已,是對TCP/IP協議的抽象,從而形成了我們知道的一些最基本的函數接口。
一.利用Socket建立網絡連接的步驟
建立Socket連接至少需要一對套接字,其中一個運行於客戶端,稱爲ClientSocket ,另一個運行於服務器端,稱爲ServerSocket 。
套接字之間的連接過程分爲三個步驟:服務器監聽,客戶端請求,連接確認。
1。服務器監聽:服務器端套接字並不定位具體的客戶端套接字,而是處於等待連接的狀態,實時監控網絡狀態,等待客戶端的連接請求。
2。客戶端請求:指客戶端的套接字提出連接請求,要連接的目標是服務器端的套接字。爲此,客戶端的套接字必須首先描述它要連接的服務器的套接字,指出服務器端套接字的地址和端口號,然後就向服務器端套接字提出連接請求。
3。連接確認:當服務器端套接字監聽到或者說接收到客戶端套接字的連接請求時,就響應客戶端套接字的請求,建立一個新的線程,把服務器端套接字的描述發給客戶端,一旦客戶端確認了此描述,雙方就正式建立連接。而服務器端套接字繼續處於監聽狀態,繼續接收其他客戶端套接字的連接請求。
二.Socket 一般有兩種類型:TCP 套接字和 UDP 套接字
1.使用 TCP 通信
TCP 服務器端工作的主要步驟如下:
步驟 1 調用 ServerSocket(int port)創建一個 ServerSocket,並綁定到指定端口上。
步驟 2 調用 accept(),監聽連接請求,如果客戶端請求連接,則接受連接,返回通信套接字。
步驟 3 調 用 Socket 類 的 getOutputStream() 和 getInputStream() 獲 取 輸 出 和 輸 入 流,開始網絡數據的發送和接收。
步驟 4 關閉通信套接字。
// 創建一個 ServerSocket 對象
ServerSocket serverSocket = null;
try {
// TCP_SERVER_PORT 爲指定的綁定端口,爲 int 類型
serverSocket = new ServerSocket(TCP_SERVER_PORT);
// 監聽連接請求
Socket socket = serverSocket.accept();
// 寫入讀 Buffer 中
BufferedReader in = new BufferedReader(new
// 獲取輸入流
InputStreamReader(socket.getInputStream()));
// 放到寫 Buffer 中
BufferedWriter out = new BufferedWriter(new
// 獲取輸出流
OutputStreamWriter(socket.getOutputStream()));
// 讀取接收信息,轉換爲字符串
String incomingMsg = in.readLine() + System.getProperty("line.separator");
// 生成發送字符串
String outgoingMsg = "goodbye from port " + TCP_SERVER_PORT +
System.getProperty("line.separator");
// 將發送字符串寫入上面定義的 BufferedWriter 中
out.write(outgoingMsg);
// 刷新,發送
out.flush();
// 關閉
socket.close();
} catch (InterruptedIOException e) {
// 超時錯誤
e.printStackTrace();
// IO 異常
} catch (IOException e) {
// 打印錯誤
e.printStackTrace();
} finally {
// 判定是否初始化 ServerSocket 對象,如果初始化則關閉 serverSocket
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
TCP 客戶端工作的主要步驟如下:
步驟 1 調用 Socket() 創建一個流套接字,並連接到服務器端。
步驟 2 調 用 Socket 類 的 getOutputStream() 和 getInputStream() 方 法 獲 取 輸 出 和 輸 入流,開始網絡數據的發送和接收。
步驟 3 關閉通信套接字。
try {
// 初始化 Socket,TCP_SERVER_PORT 爲指定的端口,int 類型
Socket socket = new Socket("localhost", TCP_SERVER_PORT);
// 獲取輸入流
BufferedReader in = new BufferedReader(new
InputStreamReader(socket.getInputStream()));
// 生成輸出流
BufferedWriter out = new BufferedWriter(new
OutputStreamWriter(socket.getOutputStream()));
// 生成輸出內容
String outMsg = "TCP connecting to " + TCP_SERVER_PORT +
System.getProperty("line.separator");
// 寫入
out.write(outMsg);
// 刷新,發送
out.flush();
// 獲取輸入流
String inMsg = in.readLine() + System.getProperty("line.separator");
Log.i("TcpClient", "received: " + inMsg);
// 關閉連接
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
2.使用 UDP 通信
UDP 服務器端工作的主要步驟如下:
步驟 1 調用 DatagramSocket(int port) 創建一個數據報套接字,並綁定到指定端口上。
步驟 2 調用 DatagramPacket(byte[]buf,int length),建立一個字節數組以接收 UDP 包。
步驟 3 調用 DatagramSocket 類的 receive(),接受 UDP 包。
步驟 4 關閉數據報套接字。
// 接收的字節大小,客戶端發送的數據不能超過 MAX_UDP_DATAGRAM_LEN
byte[] lMsg = new byte[MAX_UDP_DATAGRAM_LEN];
// 實例化一個 DatagramPacket 類
DatagramPacket dp = new DatagramPacket(lMsg, lMsg.length);
// 新建一個 DatagramSocket 類
DatagramSocket ds = null;
try {
// UDP 服務器監聽的端口
ds = new DatagramSocket(UDP_SERVER_PORT);
// 準備接收數據
ds.receive(dp);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 如果 ds 對象不爲空,則關閉 ds 對象
if (ds != null) {
ds.close();
}
}
UDP 客戶端工作的主要步驟如下:
步驟 1 調用 DatagramSocket() 創建一個數據包套接字。
步驟 2 調用 DatagramPacket(byte[]buf,int offset,int length,InetAddress address,int port),建立要發送的 UDP 包。
步驟 3 調用 DatagramSocket 類的 send() 發送 UDP 包。
步驟 4 關閉數據報套接字。
// 定義需要發送的信息
String udpMsg = "hello world from UDP client " + UDP_SERVER_PORT;
// 新建一個 DatagramSocket 對象
DatagramSocket ds = null;
try {
// 初始化 DatagramSocket 對象
ds = new DatagramSocket();
// 初始化 InetAddress 對象
InetAddress serverAddr = InetAddress.getByName("127.0.0.1");
DatagramPacket dp;
// 初始化 DatagramPacket 對象
dp = new Datagram
Packet(udpMsg.getBytes(), udpMsg.length(), serverAddr, UDP_SERVER_PORT);
// 發送
ds.send(dp);
// 異常處理
// Socket 連接異常
}catch (SocketException e) {
e.printStackTrace();
// 不能連接到主機
}catch (UnknownHostException e) {
e.printStackTrace();
// 數據流異常
} catch (IOException e) {
e.printStackTrace();
// 其他異常
} catch (Exception e) {
e.printStackTrace();
} finally {
// 如果 DatagramSocket 已經實例化,則需要將其關閉
if (ds != null) {
ds.close();
}
}