標籤:需要 fixed block 包括 傳輸資料 兩台 程式設計語言 ide ble
原文地址:Java Socket編程----通訊是這樣煉成的
Java最初是作為網路程式設計語言出現的,其對網路提供了高度的支援,使得用戶端和伺服器的溝通變成了現實,而在網路編程中,使用最多的就是Socket。像大家熟悉的QQ、MSN都使用了Socket相關的技術。下面就讓我們一起揭開Socket的神秘面紗。
Socket編程網路基礎知識點:
- 兩台電腦間進行通訊需要以下三個條件
IP地址、協議、連接埠號碼:
- IP地址:定位應用所在機器的網路位置。(比如家庭住址:北京市朝陽區XX街道XX小區)
- 連接埠號碼:唯一識別到機器的指定應用。(門牌號)
- 協議:資料轉送的形式。(TCP、UDP等)
IP地址
為實現網路中不同電腦之間的通訊,每台電腦都必須有一個唯一的標識---IP地址。
連接埠
區分一台主機的多個不同應用程式,連接埠號碼範圍為0-65535,其中0-1023位為系統保留。
如:HTTP:80 FTP:21 Telnet:23
IP地址+連接埠號碼組成了所謂的Socket,Socket是網路上啟動並執行程式之間雙向通訊鏈路的終結點,是TCP和UDP的基礎。
Socket通訊端:
網路上具有唯一標識的IP地址和連接埠組合在一起才能構成唯一能識別的標識符通訊端。
Socket原理機制:
通訊的兩端都有Socket。
網路通訊其實就是Socket間的通訊。
資料在兩個Socket間通過IO傳輸 。
- Java中的網路支援
針對網路通訊的不同層次,Java提供了不同的API,其提供的網路功能有四大類:
- InetAddress:用於標識網路上的硬體資源,主要是IP地址。
- URL:統一資源定位器,通過URL可以直接讀取或寫入網路上的資料。
- Sockets:使用TCP協議實現的網路通訊Socket相關的類
- Datagram:使用UDP協議,將資料儲存在使用者資料報中,通過網路進行通訊。
InetAddress
InetAddress類代表了一個網路目標地址,包括主機名稱和IP地址資訊。
該類沒有任何構造方法。
// 獲得原生 主機名稱和IP地址InetAddress address = InetAddress.getLocalHost();String hostName = address.getHostName();//擷取電腦名稱(本機主機名稱就是電腦名稱)String hostAddress = address.getHostAddress();//擷取IP地址System.out.println("hostName: " + hostName +" &hostAddress:" + hostAddress);// 擷取遠程機器的 主機名稱和IP地址InetAddress addr = InetAddress.getByName("www.baidu.com"); // 這裡不要加協議 比如:http://www.baidu.comString domainName = addr.getHostName();//獲得主機名稱String ipName = addr.getHostAddress();//獲得IP地址System.out.println("domainName:" + domainName + " &ipName:" + ipName);
使用URL網路資源
通過URL對象的openStream()方法可以得到指定資源的輸入資料流,通過流能夠讀取或訪問網頁上的資源。
//使用URL讀取網頁內容URL url = new URL("http://www.baidu.com");InputStream is = url.openStream();//通過openStream方法擷取資源的位元組輸入資料流InputStreamReader isr = new InputStreamReader(is,"UTF-8");//將位元組輸入資料流轉換為字元輸入資料流,如果不指定編碼,中文可能會出現亂碼BufferedReader br = new BufferedReader(isr);//為字元輸入資料流添加緩衝,提高讀取效率String data = br.readLine();//讀取資料while(data!=null){ System.out.println(data);//輸出資料 data = br.readLine();}br.close();is.close();
TCP編程模型
TCP協議是連線導向的、可靠的、有序的、以位元組流的方式發送資料,通過三向交握方式建立串連,形成傳輸資料的通道,在串連中進行大量資料的傳輸,效率會稍低。
Java中基於TCP協議實現網路通訊的類:
- 用戶端的Socket類。
- 伺服器端的ServerSocket類。
Socket通訊的步驟:
- 建立ServerSocket和Socket。
- 開啟串連到Socket的輸入和輸出資料流。
- 按照TCP協議對Socket進行讀寫操作。
- 關閉輸入輸出資料流,關閉Socket。
伺服器端:
- 建立ServerSocket對象,綁定監聽連接埠。
- 通過accept()方法監聽用戶端請求。
- 串連建立後,通過輸入資料流讀取用戶端發送的請求資訊。
- 通過輸出資料流向用戶端發送響應資訊。
- 關閉相關資源。
/** * 基於TCP協議的Socket通訊,實現使用者登入,服務端 *///1、建立一個伺服器端Socket,即ServerSocket,指定綁定的連接埠,並監聽此連接埠ServerSocket serverSocket = new ServerSocket(10086);//1024-65535的某個連接埠//2、調用accept()方法開始監聽,等待用戶端的串連Socket socket = serverSocket.accept();//3、擷取輸入資料流,並讀取用戶端資訊InputStream is = socket.getInputStream();InputStreamReader isr = new InputStreamReader(is);BufferedReader br = new BufferedReader(isr);String info = null;while ((info = br.readLine()) != null) { System.out.println("我是伺服器,用戶端說:" + info);}socket.shutdownInput();//關閉輸入資料流//4、擷取輸出資料流,響應用戶端的請求OutputStream os = socket.getOutputStream();PrintWriter pw = new PrintWriter(os);pw.write("歡迎您!");pw.flush();//5、關閉資源pw.close();os.close();br.close();isr.close();is.close();socket.close();
用戶端:
- 建立Socket對象,指明需要已連線的服務器的地址和連接埠號碼。
- 串連建立後,通過輸出資料流向伺服器端發送請求資訊。
- 通過輸入資料流擷取伺服器響應的資訊
- 關閉相關資源。
//1、建立用戶端Socket,指定伺服器位址和連接埠Socket socket = new Socket("localhost",10086);//2、擷取輸出資料流,向伺服器端發送資訊OutputStream os = socket.getOutputStream();//位元組輸出資料流PrintWriter pw = new PrintWriter(os);//將輸出資料流封裝成列印流pw.write("使用者名稱:admin;密碼:123");pw.flush();socket.shutdownOutput();//3、擷取輸入資料流,並讀取伺服器端的響應資訊InputStream is = socket.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(is));String info = null;while((info=br.readLine())!= null){ System.out.println("我是用戶端,伺服器說:"+info);}//4、關閉資源br.close();is.close();pw.close();os.close();socket.close();
多線程實現伺服器與用戶端之間的通訊。
伺服器端迴圈調用accept()等待用戶端串連。伺服器端接收到資料後即交給一個線程進行非同步處理,然後再次等待用戶端串連。
static ExecutorService executor = Executors.newFixedThreadPool(10);public static void main(String[] args) throws Exception { /** * 基於TCP協議的Socket通訊,實現使用者登入,服務端 */ //1、建立一個伺服器端Socket,即ServerSocket,指定綁定的連接埠,並監聽此連接埠 ServerSocket serverSocket = new ServerSocket(10086);//1024-65535的某個連接埠 //2、調用accept()方法開始監聽,等待用戶端的串連 while(true) { executor.execute(new ServerTask(serverSocket.accept())); }}static class ServerTask implements Runnable { Socket socket ; public ServerTask(Socket socket) { this.socket = socket; } @Override public void run() { try { //3、擷取輸入資料流,並讀取用戶端資訊 InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String info = null; while ((info = br.readLine()) != null) { System.out.println("我是伺服器,用戶端說:" + info); } socket.shutdownInput();//關閉輸入資料流 //4、擷取輸出資料流,響應用戶端的請求 OutputStream os = socket.getOutputStream(); PrintWriter pw = new PrintWriter(os); pw.write("歡迎您!"); pw.flush(); // demo 就不放在finally裡關閉了 is.close(); isr.close(); os.close(); pw.close(); }catch (Exception e) { e.printStackTrace(); } }}
UDP編程模型
UDP協議(使用者資料包通訊協定)是不需連線的、不可靠的、無序的,速度快。
進行資料轉送時,首先將要傳輸的資料定義成資料報(Datagram),大小限制在64k,在資料報中指明資料索要達到的Socket(主機地址和連接埠號碼),然後再將資料報發送出去。
DatagramPacket類:表示資料報包
DatagramSocket類:進行端到端通訊的類
伺服器端實現步驟:
+ 建立DatagramSocket,指定連接埠號碼 + 建立DatagramPacket + 接受用戶端發送的資料資訊 + 讀取資料
//伺服器端,實現基於UDP的使用者登入//1、建立伺服器端DatagramSocket,指定連接埠DatagramSocket socket =new DatagramSocket(10010);//2、建立暫存的資料報文,用於接受用戶端發送的資料byte[] data = new byte[1024];DatagramPacket packet =new DatagramPacket(data,data.length);//3、接受用戶端發送的資料socket.receive(packet);//此方法在接受資料報之前會一致阻塞//4、讀取資料String info = new String(data);System.out.println("我是伺服器,用戶端告訴我:"+info);//向用戶端響應資料//1、定義用戶端的地址、連接埠號碼、資料InetAddress address = packet.getAddress();int port = packet.getPort();byte[] data2 = "歡迎您!".getBytes();//2、建立資料報,包含響應的資料資訊DatagramPacket packet2 = new DatagramPacket(data2,data2.length,address,port);//3、響應用戶端socket.send(packet2);//4、關閉資源socket.close();
用戶端實現步驟:
- 定義發送訊息。
- 建立DatagramPacket,包含將要發送的訊息。
- 建立DatagramSocket。
- 發送資料。
//用戶端//1、定義伺服器的地址、連接埠號碼、資料InetAddress address = InetAddress.getByName("localhost");int port = 10010;byte[] data = "使用者名稱:admin;密碼:123".getBytes();//2、建立資料報,包含發送的資料資訊DatagramPacket packet = new DatagramPacket(data, data.length, address, port);//3、建立DatagramSocket對象DatagramSocket socket = new DatagramSocket();//4、向伺服器發送資料socket.send(packet);//接受伺服器端響應資料//======================================//1、建立資料報,用於接受伺服器端響應資料byte[] data2 = new byte[1024];DatagramPacket packet2 = new DatagramPacket(data2, data2.length);//2、接受伺服器響應的資料socket.receive(packet2);String raply = new String(data2, 0, packet2.getLength());System.out.println("我是用戶端,伺服器說:" + raply);//4、關閉資源socket.close();
注意問題:
1、多線程的優先順序問題:
根據實際的經驗,適當的降低優先順序,否側可能會有程式運行效率低的情況
2、是否關閉輸出資料流和輸入資料流:
對於同一個socket,如果關閉了輸出資料流,則與該輸出資料流關聯的socket也會被關閉,所以一般不用關閉流,直接關閉socket即可
3、使用TCP通訊傳輸對象,IO中序列化部分
4、socket編程傳遞檔案,IO流部分
Java Socket編程基礎篇