Java如何利用Socket進行數據讀寫
利用Socket進行數據讀寫
Java中和網絡有關的類分為四種:InetAddress(網絡信息標識)、URL(統一資源定位器,讀寫網絡數據)、Sockets(利用TCP/IP實現網絡通信)、Datagram(UDP數據報通信)
InetAddress與URL
通過InetAddress可以獲取計算機名、IP地址等信息
public static void main(String[] args) throws UnknownHostException { InetAddress address=InetAddress.getLocalHost(); // 通過靜態方法生成InetAddress實例 System.out.println("計算機名稱:"+ address.getHostName()); System.out.println("IP地址:"+ address.getHostAddress()); byte[] ipBytes=address.getAddress(); // 以數組的形式獲取IP System.out.println("IP地址數組:"+ Arrays.toString(ipBytes)); System.out.println(address); //打印實例,輸出:主機名/IP InetAddress address1=InetAddress.getByName("DELL-T"); // 通過主機名獲取實例 System.out.println(address1.getHostAddress()); InetAddress address2=InetAddress.getByName("192.168.80.1"); //通過IP字符串獲取實例 System.out.println(address2.getHostName()); }
url用於唯一標識網絡上的資源位置,由協議名和資源名兩部分組成,例如https://www.baidu.com/s?wd=Java#p1,https為協議名,後面為資源名。java.net包中的URL類用於操作url相關信息,其使用如下:
URL baidu = new URL("https://www.baidu.com"); // 通過網址創建url實例 URL url = new URL(baidu, "s?wd=Java#p1"); // 在url對象的基礎上拼接成新的url實例 //查看url相關信息 System.out.println("協議" + url.getProtocol()); System.out.println("主機" + url.getHost()); System.out.println("端口" + url.getPort()); System.out.println("文件路徑" + url.getFile()); System.out.println("相對路徑" + url.getRef()); System.out.println("查詢內容" + url.getQuery());
結果如下:
通過url的openStream()方法可以獲取url對應的網絡資源,打開輸入流之後便可讀取url內容
InputStream inputStream = url.openStream(); //打開網絡資源輸入流 BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); //緩沖讀取內容 String line = br.readLine(); while (line != null) { System.out.println(line); line = br.readLine(); } br.close(); inputStream.close();
Socket通信
Sockets是指TCP協議的基礎上實現的面向連接、可靠、有序、面向字節流的網絡通信類,主要包括兩個類,在服務器端的ServerSocket類和在客戶端的Socket類,其通信流程如下所示
如下所示為客戶端向服務器發送登錄請求,服務器返回相應的Socket通信示例過程:
//服務器端,先啟動 public class ServerSocketDemo { public static void main(String[] args) { try { //1、創建服務器端ServerSocket對象,綁定監聽的端口號6666 ServerSocket serverSocket = new ServerSocket(6666); //2、調用accept()方法監聽開始,等待客戶端連接 System.out.println("服務器端等待客戶端連接。。。"); Socket socket = serverSocket.accept(); //3、通過輸入流讀取客戶端傳來的信息 InputStream inputStream = socket.getInputStream(); //獲取字節輸入流 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));//包裝為緩沖字符流 String info; while ((info = bufferedReader.readLine()) != null) System.out.println("收到客戶端信息:" + info); InetAddress address = socket.getInetAddress(); // 獲取客戶端的InetAddress信息 System.out.println("當前客戶端的IP:" + address.getHostAddress()); socket.shutdownInput(); //關閉socket輸入流 //4、通過輸出流向客戶端返回相應信息 OutputStream outputStream = socket.getOutputStream(); //獲取輸出流 PrintWriter printWriter = new PrintWriter(outputStream); //將輸出流包裝為打印流 printWriter.write("歡迎登錄!"); printWriter.flush(); socket.shutdownOutput(); //關閉socket輸出流 //5、關閉資源流 printWriter.close(); outputStream.close(); bufferedReader.close(); inputStream.close(); socket.close(); serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } }
//客戶端 public class ClientSocketDemo { public static void main(String[] args) { try { //1、創建客戶端Socket對象,指定要連接的服務器和端口 Socket socket = new Socket("localhost", 6666); //2、通過輸出流向服務器發送信息 OutputStream outputStream = socket.getOutputStream(); //獲取輸出流 PrintWriter printWriter = new PrintWriter(outputStream); //將輸出流包裝為打印流 printWriter.write("用戶名:小明;密碼:1234"); printWriter.flush(); socket.shutdownOutput(); //3、通過輸入流接收服務器的返回信息 InputStream inputStream = socket.getInputStream(); //獲取字節輸入流 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));//包裝為緩沖字符流 String info; while ((info = bufferedReader.readLine()) != null) System.out.println("收到服務器端相應:" + info); socket.shutdownInput(); //4、關閉流資源 bufferedReader.close(); inputStream.close(); printWriter.close(); outputStream.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } }
UDP通信
UDP是無連接、不可靠、無序的傳輸協議,但其傳輸速度較快,因此常用於對速度敏感、不要求太高準去率的傳輸過程。在傳輸時,首先將要傳輸的數據封裝成數據報(Datagram),在數據報中定義數據要目的主機和端口號(Socket),然後再將數據發送出去。Java中的DatagramPacket類表示數據包,DatagramSocket類表示端到端的UDP通信。如下所示為服務器端和客戶端通過UDP通信的過程:
//服務器端 public class UDPServer { public static void main(String[] args) throws IOException { //服務器端接收客戶端信息 //1、創建非服務器端的UDPsocket對象並指定端口 DatagramSocket socket = new DatagramSocket(6666); //2、創建用於接受客戶端數據的數據報 byte[] data = new byte[1024]; //用於接收數據的字節數組 DatagramPacket packet = new DatagramPacket(data, data.length); //3、接收客戶端的數據 System.out.println("等待客戶端數據中。。。"); socket.receive(packet); //4、讀取接收在data中的字節數組轉化為字符串 String s = new String(data, 0, packet.getLength()); System.out.println("服務器端收到的數據:" + s); //服務器向客戶端發送響應信息 //1、定義響應信息與客戶端的地址和端口 byte[] response = "歡迎您!".getBytes(); InetAddress clientAddress = packet.getAddress(); //從客戶端發來的數據報中得到其IP地址 int port = packet.getPort(); //2、創建響應數據報 DatagramPacket responsePacket = new DatagramPacket(response, response.length, clientAddress, port); //3、發送數據報 socket.send(responsePacket); //4、關閉資源 socket.close(); } }
//客戶端 public class UDPClient { public static void main(String[] args) throws IOException { //客戶端向服務器發送數據報 //1、創建數據報,包含要發送的數據、目標服務器地址、端口號 byte[] data = "用戶名:小明;密碼:1234".getBytes(); InetAddress address = InetAddress.getByName("localhost"); DatagramPacket packet = new DatagramPacket(data, data.length, address, 6666); //2、創建DatagramSocket對象 DatagramSocket socket = new DatagramSocket(); //3、發送數據包 socket.send(packet); //客戶端接收服務器響應數據報 //1、創建接收數據報的packet byte[] resData = new byte[1024]; DatagramPacket resPacket = new DatagramPacket(resData, resData.length); //2、接收響應數據 socket.receive(resPacket); //3、讀取響應數據 String res = new String(resData, 0, resPacket.getLength()); System.out.println("客戶端收到響應:" + res); //4、關閉資源 socket.close(); } }
Socket通信中,持續單向讀寫的同步問題
在Java網絡編程中,有的時候客戶端或者服務端需要持續向對方發送數據,有的時候發送速度超過瞭接收速度,就會出現一次讀兩份數據,甚至更多的現象發生。
如何解決這個問題呢?
我們可以每次發送一行數據,然後另一邊每次讀入一行數據。這邊一行一行地發送,那邊讀完一行瞭再去讀下一行,這樣就會每次發送的數據以行為單位,就可以避免一次接受多條連著的數據瞭。因為服務端和客戶端都是Socket操作,其實二者都是一樣的,所以沒有具體區分服務端還是客戶端。
發送端Socket操作(Socket send)
//獲得發送端socket的OutputStream的PrintWriter封裝對象 PrintWriter printWriter = new PrintWriter(send.getOutputStream()); //持續發送數據 for (int i = 0; i < 500; i++) { String message = "Hello World"; //發送一行數據 printWriter.println(message); //將緩沖區數據發送出去 printWriter.flush(); }
接收端Socket操作(Socket receive)
//獲得接收端socket的InputStream的BufferedReader封裝對象 BufferedReader reader=new BufferedReader(new InputStreamReader(receive.getInputStream())); //一直接收數據 while (true){ String message = reader.readLine(); System.out.println(message); }
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。