1、網絡基礎知識html
一、兩臺計算機要經過網絡進行通訊,必須具有:java
1)惟一的標識(IP地址);編程
2)須要共同的語言(協議);數組
3)辨別不一樣應用程序(端口號)。服務器
二、瞭解相關概念網絡
1)IP地址:多線程
每臺計算機的惟一標識,用來區分網絡中的不一樣主機,是兩臺主機進行網絡通訊必不可少的。2)協議:socket
(1)TCP/IP協議:目前世界上應用最爲普遍的協議。是以TCP和IP爲基礎的不一樣層次上多個協議的集合。也稱爲:TCP/IP協議族 或者 TCP/IP協議棧。(TCP: Transmission Control Protocol -- 傳輸控制協議;IP :Internet Protocol -- 互聯網協議)this
3)CP/IP模型(網絡分層):url
(1)物理層(如網線、網線槽)
(2)數據鏈路層
(3)網絡層
(4)傳輸層:TCP/IP協議
(5)應用層:HTTP超文本傳輸協議、FTP文件傳輸協議、SMTP簡單郵件傳送協議、Telnet遠程登陸服務。
4)端口號:
(1)用於區分不一樣的應用程序;
(2)端口號範圍爲0-65535,其中0-1023爲系統所保留;
(3)IP地址和端口號組成了所謂的Socket,Socket是網絡上運行的程序之間雙向通訊鏈路的終結點,是TCP和UDP的基礎。
(4)經常使用端口號-- http: 80; ftp; 21; telnet; 23。
5)JAVA中得網絡支持。針對網絡通訊的不一樣層次,Java提供的網絡功能有四大類:
(1)InetAddress:用於標識網絡上的硬件資源。(IP地址)
(2)URL:統一資源定位符---經過URL能夠直接讀取或寫入網絡上得數據。
(3)Sockets:使用TCP協議實現網絡通訊的Socket相關的類。
(4)Datagram:使用UDP協議,將數據保存在數據報中,經過網絡進行通訊。
1)InetAddress類沒有構造方法,因此不能直接new出一個對象;但能夠經過InetAddress類的靜態方法得到InetAddress的對象:如
InetAddress.getLocalHost();
InetAddress.getByName();
2)類主要方法:
String - address.getHostName();
String - address.getHostAddress();
public static InetAddress getByName(String host) throws UnknownHostException
// 在給定主機名的狀況下肯定主機的 IP 地址。主機名能夠是機器名(如 "java.sun.com"),也能夠是其 IP 地址的文本表示形式
3)InetAddress使用示例代碼:
import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; /** * InetAddress類的基本使用 */ public class InetAddressDemo { public static void main(String[] args) throws UnknownHostException { /* * 獲取本地主機信息 */ InetAddress address = InetAddress.getLocalHost(); System.out.println("主機名稱" + address.getHostName()); System.out.println("IP地址:" + address.getHostAddress()); byte[] bytes = address.getAddress(); // 以獲取字節數組的形式獲取地址 System.out.println("本身數組形式的ip: " + Arrays.toString(bytes)); System.out.println(address);// 直接輸出InetAddress對象 System.out.println(); /* * 根據機器名獲取InetAddresss實例 */ InetAddress address2 = InetAddress.getByName("Moonlight"); System.out.println("計算機名:" + address2.getHostName()); System.out.println("IP地址:" + address2.getHostAddress()); System.out.println(); /* * 根據IP獲取InetAddress實例 */ InetAddress address3 = InetAddress.getByName("192.168.1.102"); System.out.println("計算機名:" + address3.getHostName()); System.out.println("IP地址:" + address3.getHostAddress()); System.out.println(); /* * 獲取其它地址 */ InetAddress address4 = InetAddress.getByName("baidu.com"); System.out.println("計算機名:" + address4.getHostName()); System.out.println("IP地址:" + address4.getHostAddress()); System.out.println(); } }
1)簡介:
(1)URL(Uniform Resource Locator)統一資源定位符,表示Internet上某一資源的地址
(2)URL由兩部分組成:協議名稱和資源名稱,中間用冒號隔開
(3)在java.net包中,提供了URL類來表示URL
2)使用URL讀取網頁內容
(1)經過URL對象的openStream()方法能夠獲得指定資源的輸入流
(2)經過輸入流能夠讀取、訪問網絡上的數據
3)URL類使用示例代碼:
import java.net.MalformedURLException; import java.net.URL; /** * URL經常使用方法 */ public class URLDemo { public static void main(String[] args) throws MalformedURLException { // 建立URL實例 URL url = new URL("http://www.baidu.com"); URL url2 = new URL(url, "/index.html?uname=1#test"); // 在原有的URL資源上再建立URL實例,#後面表示錨點 System.out.println("協議" + url2.getProtocol()); System.out.println("主機" + url2.getHost()); // 若是未指定端口號,則使用默認的端口號,此時getPort()返回-1 System.out.println("端口" + url2.getPort()); System.out.println("文件路徑" + url2.getPath()); System.out.println("文件名稱:" + url2.getFile()); System.out.println("相對路徑" + url2.getRef()); System.out.println("查詢字符串" + url2.getQuery()); } }
一、Socket通訊模型
1)上圖的通訊模型的順序爲:
(1)先創建服務端監聽Soket,等待客戶端請求。
(2)客戶端建立socket,向服務端發送請求。
(3)服務端接收請求,並建立鏈接socket到此步驟時,服務端與客戶端創建了鏈接。
(4)服務端和客戶端開始通訊(InputStream、OutputStream)。
(5)最後關閉socket與相關資源。
二、Socket實現TCP編程通訊的實現步驟
1)服務端:
(1)建立ServerSocket對象,綁定監聽端口
(2)經過accept()方法監聽客戶端的請求
(3)創建鏈接後,經過輸入流讀取客戶端發送的請求信息
(4)經過輸出流向客戶端發送相應信息
(5)關閉相關資源
代碼示例:
import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; /** * 服務端 * 基於TCP協議的Socket通訊 -- 單線程 */ public class TCPServer { public static void main(String[] args) { try { // 1.建立一個服務器端Socket,即ServerSocket,指定綁定的端口,並監聽 ServerSocket serverSocket = new ServerSocket(8888); // 2.調用accept()方法開始監聽,等待客戶端的鏈接 System.out.println("服務器即將啓動,等待客戶端的鏈接***"); Socket socket = serverSocket.accept(); // 3.獲取輸入流,並讀取客戶端信息 InputStream is = socket.getInputStream(); InputStreamReader irs = new InputStreamReader(is); BufferedReader br = new BufferedReader(irs); 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(); irs.close(); is.close(); socket.close(); serverSocket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
2)客戶端:
(1)建立Socket對象,指明須要鏈接的服務器的地址和端口號
(2)鏈接創建後,經過輸出流向服務器端發送請求信息
(3)經過輸入流獲取服務器相應的信息
(4)關閉相關資源
代碼示例:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; /** * 客戶端 * 基於TCP協議的Socket通訊 */ public class TCPClient { public static void main(String[] args) { try { // 1.建立客戶端Socket,指定服務器地址和端口 Socket socket = new Socket("localhost", 8888); // 2.獲取輸出流,向服務器端發送信息 OutputStream os = socket.getOutputStream();//字節輸出流 PrintWriter pw = new PrintWriter(os); pw.write("客戶端發信息來啦~~"); 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(); } catch (IOException e) { e.printStackTrace(); } } }
三、應用多線程來實現服務器與多客戶端之間的通訊的基本基本步驟
(1)服務器端建立ServerSocket,循環調用accept()等待客戶端鏈接
(2)客戶端建立一個socket並請求和服務器端鏈接
(3)服務器端接收客戶端請求,建立socket與該客戶創建專線鏈接
(4)創建鏈接的兩個socket在一個單獨的線程上對話
(5)服務器端繼續等待新的鏈接
代碼示例:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; /** * 服務端 * 基於TCP協議的Socket通訊 -- 多線程實現多客戶的通訊 */ public class TCPServerMulConnection { public static void main(String[] args) { try { // 建立一個服務器端Socket,即ServerSocket,指定綁定的端口,並監聽 ServerSocket serverSocket = new ServerSocket(8888); // 調用accept()方法開始監聽,等待客戶端的鏈接 System.out.println("服務器即將啓動,等待客戶端的鏈接***"); Socket socket = null; int count = 0; // 記錄客戶端的鏈接 // 循環監聽等待客戶端的鏈接 while (true) { // 調用accept()方法開始監聽,等待客戶端的鏈接 socket = serverSocket.accept(); // 建立一個新的線程 ServerThreadHelper serverThread = new ServerThreadHelper(socket); //serverThread.setPriority(4); //可設置線程優先級(優先級默認爲5,數字越小,優先級越低;未設置優先級可能致使運行時速度很是慢,可適當下降) // 啓動線程 serverThread.start(); count++; // 統計客戶端的數量 InetAddress address = socket.getInetAddress(); System.out.println("第 " + count + " 個客戶端鏈接成功!此客戶端的ip爲:" + address.getHostAddress()); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 服務器端線程處理類 */ class ServerThreadHelper extends Thread{ // 和本線程相關的socket Socket socket = null; public ServerThreadHelper(Socket socket){ this.socket = socket; } // 線程執行的操做,響應客戶端請求 public void run(){ InputStream is = null; InputStreamReader irs = null; BufferedReader br = null; OutputStream os = null; PrintWriter pw = null; try { // 1.獲取輸入流,並讀取客戶端信息 is = socket.getInputStream(); irs = new InputStreamReader(is); br = new BufferedReader(irs); String info = null; while((info=br.readLine()) != null){ System.out.println("服務器接收到消息:" + info); } socket.shutdownInput();//關閉輸入流 // 2.獲取輸出流,響應客戶端請求 os = socket.getOutputStream(); pw = new PrintWriter(os); pw.write("終於等到你!"); pw.flush(); } catch (IOException e) { e.printStackTrace(); } finally { // 3.關閉資源 try { if (pw!=null) { pw.close(); } if (os!=null) { os.close(); } if (br!=null) { br.close(); } if (irs!=null) { irs.close(); } if (is!=null) { is.close(); } if (socket!=null) { socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
一、UDP編程簡介
(1)UDP協議(用戶數據報協議)是無鏈接、不可靠、無序的,特色是速度比較快
(2)進行數據傳輸時,首先要將要傳輸的數據定義成數據報(Datagram),在數據報中指明數據所要達到的Socket(主機地址和端口號),而後再將數據報發送出去
(3)相關的操做類:DatagramPacket:表示數據報包 DatagramSocket:進行端到端通訊的類
二、Socket實現UDP編程
1)服務器端實現步驟
(1)建立DatagramSocket,指定端口號
(2)建立DatagramPacket,用於接收客戶端請求
(3)接收客戶端發送的數據信息
(4)讀取數據
(5)關閉資源
示例代碼:
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; /** * 服務端 * 基於UDP實現Socket通訊 */ public class UDPServer { public static void main(String[] args) throws IOException { /* * 接收客戶發送的數據 */ // 1.建立服務器端DatagramSocket,指定端口 DatagramSocket socket = new DatagramSocket(8800); // 2.建立數據報,用於接收客戶端發送的數據 byte[] data = new byte[1024]; DatagramPacket packet = new DatagramPacket(data, data.length); // 3.接收客戶端發送的數據 System.out.println("服務器已啓動,等待接收數據報中……"); socket.receive(packet); // 此方法在接收到數據報以前會一直阻塞 // 4.讀取數據 String info = new String(data, 0, packet.getLength()); 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(); } }
2)客戶端實現步驟
(1)定義發送信息
(2)建立DatagramPacket,包含將要發送的信息
(3)建立DatagramSocket
(4)發送數據(經過DatagramSocket發送)
(5)關閉資源
示例代碼:
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.UnknownHostException; /** * 客戶端 * 基於UDP實現Socket通訊 */ public class UDPClient { public static void main(String[] args) throws IOException { /* * 發送消息給服務端 */ // 1.定義服務器的地址、端口號、數據報 InetAddress address = InetAddress.getByName("localhost"); int port = 8800; byte[] data = "你好!我是客戶端。".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); // 3.讀取數據 String reply = new String(data2, 0, packet2.getLength()); System.out.println("客戶端接收到新信息:" + reply); // 4.關閉資源 } }
一、使用多線程編寫網絡程序時,能夠將線程的優先級下降,線程的優先級默認是五,數字越小,優先級越低;未設置優先級可能致使運行時速度很是慢,可適當下降。
二、對於同一個socket,若是關閉了輸出流,則與該輸出流相關的socket也會被關閉,因此通常不用關閉流,直接關閉socet便可。
三、能夠將一個對象序列化以後,經過流的方式在網絡上傳輸
ObjectOutputStream oos = new ObjectOutputStream(os); oos.writeObject(User);
四、網絡上傳輸文件,也是將文件轉換爲流,經過流的方式在網絡上傳輸
BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream(new File("d://")));