1 Java中的Socket編程接口介紹
Java為Socket編程封裝了幾個重要的類。
1.1 Socket類
Socket類實現了一個客戶端socket,作為兩台機器通信的終端,默認采用的傳輸層協議為TCP,是一個可靠傳輸的協議。Socket類除了構造函數返回一個socket外,還提供了connect, getOutputStream, getInputStream和close方法。connect方法用於請求一個socket連接,getOutputStream用於獲得寫socket的輸出流,getInputStream用於獲得讀socket的輸入流,close方法用於關閉一個流。
1.2 DatagramSocket類
DatagramSocket類實現了一個發送和接收數據報的socket,傳輸層協議使用UDP,不能保證數據報的可靠傳輸。DataGramSocket主要有send, receive和close三個方法。send用於發送一個數據報,Java提供了DatagramPacket對象用來表達一個數據報。receive用於接收一個數據報,調用該方法后,一直阻塞接收到直到數據報或者超時。close是關閉一個socket。
1.3 ServerSocket類
ServerSocket類實現了一個服務器socket,一個服務器socket等待客戶端網絡請求,然后基於這些請求執行操作,並返回給請求者一個結果。ServerSocket提供了bind、accept和close三個方法。bind方法為ServerSocket綁定一個IP地址和端口,並開始監聽該端口。accept方法為ServerSocket接受請求並返回一個Socket對象,accept方法調用后,將一直阻塞直到有請求到達。close方法關閉一個ServerSocket對象。
1.4 SocketAddress
SocketAddress提供了一個socket地址,不關心傳輸層協議。這是一個虛類,由子類來具體實現功能、綁定傳輸協議。它提供了一個不可變的對象,被socket用來綁定、連接或者返回數值。
1.5 InetSocketAddress
InetSocketAddress實現了IP地址的SocketAddress,也就是有IP地址和端口號表達Socket地址。如果不制定具體的IP地址和端口號,那么IP地址默認為本機地址,端口號隨機選擇一個。
1.6. DatagramPacket
DatagramSocket是面向數據報socket通信的一個可選通道。數據報通道不是對網絡數據報socket通信的完全抽象。socket通信的控制由DatagramSocket對象實現。DatagramPacket需要與DatagramSocket配合使用才能完成基於數據報的socket通信。
2. 基於TCP的Socket編程
上面描述了Java對Socket編程提供的接口,本節介紹如何實現一個基於TCP連接的Socket通信。
下面例子是Server端等待從Client端接收一條消息,然后再給客戶端發送一個消息。
服務器端首先實例化ServerSocket對象,然后為其綁定一個本機地址,並開始監聽。一直阻塞狀態下等待客戶端請求,當獲得客戶端連接請求后,返回一個socket對象。然后用這個socket接收一條消息,並發送一條消息。代碼如下:
package server.socket.java; import java.io.IOException; import java.io.PrintWriter; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress; public class SocketTcp { static private String TAG = "SocketTcp: "; public static void main(String[] args){ try { ServerSocket server = new ServerSocket(); SocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), 10001); server.bind(address); System.out.println("==waiting for being connected..."); Socket client = server.accept(); System.out.println("==connected with " + client.getRemoteSocketAddress() ); PrintWriter socketOut = new PrintWriter(client.getOutputStream()); System.out.println("==waiting message from client..."); byte buf[] = new byte[1024]; if ( client.getInputStream().read(buf) > 0 ) { System.out.println("Receive Message: " + new String(buf)); } System.out.println("==sending message to client..."); String sendStr = "This is the message for client."; socketOut.write(sendStr); socketOut.flush(); socketOut.close(); client.close(); server.close(); } catch (IOException e) { System.out.println(TAG + e.getMessage()); e.printStackTrace(); } } }
客戶端首先實例化一個socket對象,用這個對象連接服務器端。連接成功后,發送一條消息,然后等待接收一條消息。代碼如下:
package client.socket.java; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; public class SocketTcp { static private String TAG = "SocketTcp: "; public static void main(String[] args){ try { final Socket socket = new Socket(); SocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), 10001); System.out.println("==connecting to server ..."); socket.connect(address); PrintWriter socketOut = new PrintWriter(socket.getOutputStream()); BufferedReader socketIn = new BufferedReader( new InputStreamReader(socket.getInputStream()) ); String sendStr = "This is the message for server."; System.out.println("==sending message to server ..."); socketOut.write(sendStr); socketOut.flush(); System.out.println("==waiting message from server ..."); String receiveStr = socketIn.readLine(); System.out.println("Receive Message: " + receiveStr); socketOut.close(); socketIn.close(); socket.close(); } catch (IOException e) { System.out.println(TAG + e.getMessage()); e.printStackTrace(); } finally { } } }
服務器端運行結果:
==waiting for being connected... ==connected with /172.26.176.69:53912 ==waiting message from client... Receive Message: This is the message for server.
客戶端運行結果:
==connecting to server ... ==sending message to server ... ==waiting message from server ... Receive Message: This is the message for client.
3 基於UDP的Socket編程示例
基於UDP的Socket編程與基於TCP的socket編程稍有不同,socket server和client都用DatagramSocket實現。
下面例子是Server端等待從Client端接收一條消息,然后再給客戶端發送一個消息。
服務器端首先實例化DatagramSocket對象,然后為其綁定一個本機地址,並開始監聽。一直阻塞狀態下等待從客戶端接收數據報。然后從數據報中獲取數據報的源地址,然后用這個源地址作為目的地址打包一個數據報,然后發送出去。代碼如下:
package server.socket.java; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.SocketException; import java.net.UnknownHostException; public class SocketUdp { final private static String TAG = "SocketUdp: "; public static void main(String args[]) { DatagramSocket socket = null; DatagramPacket datapacket = null; InetSocketAddress address = null; try { address = new InetSocketAddress(InetAddress.getLocalHost(), 7778); socket = new DatagramSocket(address); // socket.bind(address); byte buf[] = new byte[1024]; datapacket = new DatagramPacket(buf, buf.length); System.out.println("==block for receive messages..."); socket.receive(datapacket); buf = datapacket.getData(); InetAddress addr = datapacket.getAddress(); int port = datapacket.getPort(); System.out.println("Message Content: " + new String(buf) ); System.out.println("Receive From " + addr + ":" + port); SocketAddress toAddress = datapacket.getSocketAddress(); String sendStr = "I'm Server, this is the message for client."; buf = sendStr.getBytes(); datapacket = new DatagramPacket(buf, buf.length); datapacket.setSocketAddress(toAddress); socket.send(datapacket); System.out.println("==message sended"); } catch (UnknownHostException e) { System.out.println(TAG + e.getMessage()); e.printStackTrace(); } catch (SocketException e) { System.out.println(TAG + e.getMessage()); e.printStackTrace(); } catch (IOException e) { System.out.println(TAG + e.getMessage()); e.printStackTrace(); } } }
客戶端首先實例化一個DatagramSocket對象。利用服務器地址和端口號作為目的地址打包一個數據報,並發送。然后等待從服務器回復的數據報。代碼如下:
package client.socket.java; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketException; import java.net.UnknownHostException; public class SocketUdp { final private static String TAG = "SocketUdp: "; public static void main(String args[]) { try { DatagramSocket getSocket = new DatagramSocket(); DatagramPacket datapacket = null; InetSocketAddress toAddress = new InetSocketAddress(InetAddress.getLocalHost(), 7778); String sendStr = "I'm client, this is the message for server."; byte buf[] = sendStr.getBytes(); datapacket = new DatagramPacket(buf, buf.length); datapacket.setSocketAddress(toAddress); getSocket.send(datapacket); System.out.println("==message sended"); System.out.println("==block for receive messages..."); getSocket.receive(datapacket); buf = datapacket.getData(); System.out.println("Message Content: " + new String(buf)); } catch (SocketException e) { System.out.println(TAG + e.getMessage()); e.printStackTrace(); } catch (UnknownHostException e) { System.out.println(TAG + e.getMessage()); e.printStackTrace(); } catch (IOException e) { System.out.println(TAG + e.getMessage()); e.printStackTrace(); } } }
服務器端運行結果:
==block for receive messages... Message Content: I'm client, this is the message for server.
客戶端運行結果:
==message sended ==block for receive messages... Message Content: I'm Server, this is the message for client.