今日內容介紹
一、網絡三要素及傳輸協議
二、實現UDP協議的發送端和接收端
三、實現TCP協議的客戶端和服務器
四、TCP上傳文件案例java
*A:網絡模型 TCP/IP協議中的四層分別是應用層、傳輸層、網絡層和鏈路層,每層分別負責不一樣的通訊功能,接下來針對這四層進行詳細地講解。 鏈路層:鏈路層是用於定義物理傳輸通道,一般是對某些網絡鏈接設備的驅動協議,例如針對光纖、網線提供的驅動。 網絡層:網絡層是整個TCP/IP協議的核心,它主要用於將傳輸的數據進行分組,將分組數據發送到目標計算機或者網絡。 傳輸層:主要使網絡程序進行通訊,在進行網絡通訊時,能夠採用TCP協議,也能夠採用UDP協議。 應用層:主要負責應用程序的協議,例如HTTP協議、FTP協議等。
*A:IP地址 在TCP/IP協議中,這個標識號就是IP地址,它能夠惟一標識一臺計算機, 目前,IP地址普遍使用的版本是IPv4,它是由4個字節大小的二進制數來表示,如:00001010000000000000000000000001。 因爲二進制形式表示的IP地址很是不便記憶和處理,所以一般會將IP地址寫成十進制的形式, 每一個字節用一個十進制數字(0-255)表示,數字間用符號「.」分開,如 「192.168.1.100」 127.0.0.1 爲本地主機地址(本地迴環地址)
*A:端口號 經過IP地址能夠鏈接到指定計算機,但若是想訪問目標計算機中的某個應用程序,還須要指定端口號。 在計算機中,不一樣的應用程序是經過端口號區分的。 端口號是用兩個字節(16位的二進制數)表示的,它的取值範圍是0~65535, 其中,0~1023之間的端口號用於一些知名的網絡服務和應用,用戶的普通應用程序須要使用1024以上的端口號,從而避免端口號被另一個應用或服務所佔用
*A:InetAddress類 /* * 表示互聯網中的IP地址 * java.net.InetAddress * 靜態方法 * static InetAddress getLocalHost() LocalHost本地主機 * 返回本地主機,返回值InetAddress對象 * * static InetAddress getByName(String hostName)傳遞主機名,獲取IP地址對象 * * 非靜態方法 * String getHoustAddress()獲取主機IP地址 * String getHoustName()獲取主機名 * */ public class InetAddressDemo { public static void main(String[] args)throws UnknownHostException { function_1(); } /* * static InetAddress getByName(String hostName)傳遞主機名,獲取IP地址對象 */ public static void function_1()throws UnknownHostException { InetAddress inet = InetAddress.getByName("www.baidu.com"); System.out.println(inet); } /* * static InetAddress getLocalHost() LocalHost本地主機 */ public static void function() throws UnknownHostException{ InetAddress inet = InetAddress.getLocalHost(); //輸出結果就是主機名,和 IP地址 System.out.println(inet.toString()); String ip = inet.getHostAddress(); String name = inet.getHostName(); System.out.println(ip+" "+name); /*String host = inet.toString(); String[] str = host.split("/"); for(String s : str){ System.out.println(s); }*/ } }
A:UDP協議 a:UDP協議概述: UDP是無鏈接通訊協議,即在數據傳輸時,數據的發送端和接收端不創建邏輯鏈接。 簡單來講,當一臺計算機向另一臺計算機發送數據時,發送端不會確認接收端是否存在,就會發出數據,一樣接收端在收到數據時,也不會向發送端反饋是否收到數據。 b:UDP協議特色: 因爲使用UDP協議消耗資源小,通訊效率高,因此一般都會用於音頻、視頻和普通數據的傳輸例如視頻會議都使用UDP協議, 由於這種狀況即便偶爾丟失一兩個數據包,也不會對接收結果產生太大影響。
*A:TCP協議 TCP協議是面向鏈接的通訊協議,即在傳輸數據前先在發送端和接收端創建邏輯鏈接,而後再傳輸數據,它提供了兩臺計算機之間可靠無差錯的數據傳輸。 在TCP鏈接中必需要明確客戶端與服務器端, 由客戶端向服務端發出鏈接請求,每次鏈接的建立都須要通過「三次握手」。 第一次握手,客戶端向服務器端發出鏈接請求,等待服務器確認 第二次握手,服務器端向客戶端回送一個響應,通知客戶端收到了鏈接請求 第三次握手,客戶端再次向服務器端發送確認信息,確認鏈接
*A:數據包和發送對象介紹: DatagramPacket數據包的做用就如同是「集裝箱」, 能夠將發送端或者接收端的數據封裝起來。然而運輸貨物只有「集裝箱」是不夠的,還須要有碼頭。 在程序中須要實現通訊只有DatagramPacket數據包也一樣不行,爲此JDK中提供的一個DatagramSocket類。 DatagramSocket類的做用就相似於碼頭,使用這個類的實例對象就能夠發送和接收DatagramPacket數據包 DatagramPacket:封裝數據 DatagramSocket:發送DatagramPacket
*A:UDP發送端 /* * 實現UDP協議的發送端: * 實現封裝數據的類 java.net.DatagramPacket 將你的數據包裝 * 實現數據傳輸的類 java.net.DatagramSocket 將數據包發出去 * * 實現步驟: * 1. 建立DatagramPacket對象,封裝數據, 接收的地址和端口 * 2. 建立DatagramSocket * 3. 調用DatagramSocket類方法send,發送數據包 * 4. 關閉資源 * * DatagramPacket構造方法: * DatagramPacket(byte[] buf, int length, InetAddress address, int port) * * DatagramSocket構造方法: * DatagramSocket()空參數 * 方法: send(DatagramPacket d) * */ public class UDPSend { public static void main(String[] args) throws IOException{ //建立數據包對象,封裝要發送的數據,接收端IP,端口 byte[] date = "你好UDP".getBytes(); //建立InetAddress對象,封裝本身的IP地址 InetAddress inet = InetAddress.getByName("127.0.0.1"); DatagramPacket dp = new DatagramPacket(date, date.length, inet,6000); //建立DatagramSocket對象,數據包的發送和接收對象 DatagramSocket ds = new DatagramSocket(); //調用ds對象的方法send,發送數據包 ds.send(dp); //關閉資源 ds.close(); } }
*A:UDP接收端 /* * 實現UDP接收端 * 實現封裝數據包 java.net.DatagramPacket 將數據接收 * 實現輸出傳輸 java.net.DatagramSocket 接收數據包 * * 實現步驟: * 1. 建立DatagramSocket對象,綁定端口號 * 要和發送端端口號一致 * 2. 建立字節數組,接收發來的數據 * 3. 建立數據包對象DatagramPacket * 4. 調用DatagramSocket對象方法 * receive(DatagramPacket dp)接收數據,數據放在數據包中 * 5. 拆包 * 發送的IP地址 * 數據包對象DatagramPacket方法getAddress()獲取的是發送端的IP地址對象 * 返回值是InetAddress對象 * 接收到的字節個數 * 數據包對象DatagramPacket方法 getLength() * 發送方的端口號 * 數據包對象DatagramPacket方法 getPort()發送端口 * 6. 關閉資源 */ public class UDPReceive { public static void main(String[] args)throws IOException { //建立數據包傳輸對象DatagramSocket 綁定端口號 DatagramSocket ds = new DatagramSocket(6000); //建立字節數組 byte[] data = new byte[1024]; //建立數據包對象,傳遞字節數組 DatagramPacket dp = new DatagramPacket(data, data.length); //調用ds對象的方法receive傳遞數據包 ds.receive(dp); } }
*A:UDP接收端的拆包 /* * 實現UDP接收端 * 實現封裝數據包 java.net.DatagramPacket 將數據接收 * 實現輸出傳輸 java.net.DatagramSocket 接收數據包 * * 實現步驟: * 1. 建立DatagramSocket對象,綁定端口號 * 要和發送端端口號一致 * 2. 建立字節數組,接收發來的數據 * 3. 建立數據包對象DatagramPacket * 4. 調用DatagramSocket對象方法 * receive(DatagramPacket dp)接收數據,數據放在數據包中 * 5. 拆包 * 發送的IP地址 * 數據包對象DatagramPacket方法getAddress()獲取的是發送端的IP地址對象 * 返回值是InetAddress對象 * 接收到的字節個數 * 數據包對象DatagramPacket方法 getLength() * 發送方的端口號 * 數據包對象DatagramPacket方法 getPort()發送端口 * 6. 關閉資源 */ public class UDPReceive { public static void main(String[] args)throws IOException { //建立數據包傳輸對象DatagramSocket 綁定端口號 DatagramSocket ds = new DatagramSocket(6000); //建立字節數組 byte[] data = new byte[1024]; //建立數據包對象,傳遞字節數組 DatagramPacket dp = new DatagramPacket(data, data.length); //調用ds對象的方法receive傳遞數據包 ds.receive(dp); //獲取發送端的IP地址對象 String ip=dp.getAddress().getHostAddress(); //獲取發送的端口號 int port = dp.getPort(); //獲取接收到的字節個數 int length = dp.getLength(); System.out.println(new String(data,0,length)+"..."+ip+":"+port); ds.close(); } }
*A:鍵盤輸入的聊天 *a:發送端: /* * 實現UDP發送,鍵盤輸入的形式 * 輸入完畢,發送給接收端 */ public class UDPSend { public static void main(String[] args) throws IOException{ Scanner sc = new Scanner(System.in); DatagramSocket ds = new DatagramSocket(); InetAddress inet = InetAddress.getByName("127.0.0.1"); while(true){ String message = sc.nextLine(); /*if("886".equals(message)){ break; }*/ byte[] date = message.getBytes(); DatagramPacket dp = new DatagramPacket(date, date.length, inet,6000); ds.send(dp); } // ds.close(); } } /* * 實現UDP接收端 * 永不停歇的接收端 */ public class UDPReceive { public static void main(String[] args)throws IOException { //建立數據包傳輸對象DatagramSocket 綁定端口號 DatagramSocket ds = new DatagramSocket(6000); //建立字節數組 byte[] data = new byte[1024]; //建立數據包對象,傳遞字節數組 while(true){ DatagramPacket dp = new DatagramPacket(data, data.length); //調用ds對象的方法receive傳遞數據包 ds.receive(dp); //獲取發送端的IP地址對象 String ip=dp.getAddress().getHostAddress(); //獲取發送的端口號 int port = dp.getPort(); //獲取接收到的字節個數 int length = dp.getLength(); System.out.println(new String(data,0,length)+"..."+ip+":"+port); } //ds.close(); } }
*A:TCP的客戶端和服務器 TCP通訊同UDP通訊同樣,都能實現兩臺計算機之間的通訊,通訊的兩端都須要建立socket對象。 區別在於,UDP中只有發送端和接收端,不區分客戶端與服務器端,計算機之間能夠任意地發送數據。 而TCP通訊是嚴格區分客戶端與服務器端的,在通訊時,必須先由客戶端去鏈接服務器端才能實現通訊, 服務器端不能夠主動鏈接客戶端,而且服務器端程序須要事先啓動,等待客戶端的鏈接。 在JDK中提供了兩個類用於實現TCP程序,一個是ServerSocket類,用於表示服務器端,一個是Socket類,用於表示客戶端。 通訊時,首先建立表明服務器端的ServerSocket對象,該對象至關於開啓一個服務,並等待客戶端的鏈接,而後建立表明客戶端的Socket對象向服務器端發出鏈接請求,服務器端響應請求,二者創建鏈接開始通訊。
*A:TCP的客戶端程序 /* * 實現TCP客戶端,鏈接到服務器 * 和服務器實現數據交換 * 實現TCP客戶端程序的類 java.net.Socket * * 構造方法: * Socket(String host, int port) 傳遞服務器IP和端口號 * 注意:構造方法只要運行,就會和服務器進行鏈接,鏈接失敗,拋出異常 * * OutputStream getOutputStream() 返回套接字的輸出流 * 做用: 將數據輸出,輸出到服務器 * * InputStream getInputStream() 返回套接字的輸入流 * 做用: 從服務器端讀取數據 * * 客戶端服務器數據交換,必須使用套接字對象Socket中的獲取的IO流,本身new流,不行 */ public class TCPClient { public static void main(String[] args)throws IOException { //建立Socket對象,鏈接服務器 Socket socket = new Socket("127.0.0.1", 8888); //經過客戶端的套接字對象Socket方法,獲取字節輸出流,將數據寫向服務器 OutputStream out = socket.getOutputStream(); out.write("服務器OK".getBytes()); socket.close(); } }
A:TCP的服務器程序accept方法 /* * 實現TCP服務器程序 * 表示服務器程序的類 java.net.ServerSocket * 構造方法: * ServerSocket(int port) 傳遞端口號 * * 很重要的事情: 必需要得到客戶端的套接字對象Socket * Socket accept() */ public class TCPServer { public static void main(String[] args) throws IOException{ ServerSocket server = new ServerSocket(8888); //調用服務器套接字對象中的方法accept() 獲取客戶端套接字對象 Socket socket = server.accept(); //經過客戶端套接字對象,socket獲取字節輸入流,讀取的是客戶端發送來的數據 InputStream in = socket.getInputStream(); byte[] data = new byte[1024]; int len = in.read(data); System.out.println(new String(data,0,len)); socket.close(); server.close(); } }
A:TCP的服務器程序讀取客戶端數據 /* * 實現TCP客戶端,鏈接到服務器 * 和服務器實現數據交換 * 實現TCP客戶端程序的類 java.net.Socket * * 構造方法: * Socket(String host, int port) 傳遞服務器IP和端口號 * 注意:構造方法只要運行,就會和服務器進行鏈接,鏈接失敗,拋出異常 * * OutputStream getOutputStream() 返回套接字的輸出流 * 做用: 將數據輸出,輸出到服務器 * * InputStream getInputStream() 返回套接字的輸入流 * 做用: 從服務器端讀取數據 * * 客戶端服務器數據交換,必須使用套接字對象Socket中的獲取的IO流,本身new流,不行 */ public class TCPClient { public static void main(String[] args)throws IOException { //建立Socket對象,鏈接服務器 Socket socket = new Socket("127.0.0.1", 8888); //經過客戶端的套接字對象Socket方法,獲取字節輸出流,將數據寫向服務器 OutputStream out = socket.getOutputStream(); out.write("服務器OK".getBytes()); socket.close(); } } /* * 實現TCP服務器程序 * 表示服務器程序的類 java.net.ServerSocket * 構造方法: * ServerSocket(int port) 傳遞端口號 * * 很重要的事情: 必需要得到客戶端的套接字對象Socket * Socket accept() */ public class TCPServer { public static void main(String[] args) throws IOException{ ServerSocket server = new ServerSocket(8888); //調用服務器套接字對象中的方法accept() 獲取客戶端套接字對象 Socket socket = server.accept(); //經過客戶端套接字對象,socket獲取字節輸入流,讀取的是客戶端發送來的數據 InputStream in = socket.getInputStream(); byte[] data = new byte[1024]; int len = in.read(data); System.out.println(new String(data,0,len)); } }
A:TCP的服務器和客戶端的數據交換 /* * 實現TCP客戶端,鏈接到服務器 * 和服務器實現數據交換 * 實現TCP客戶端程序的類 java.net.Socket * * 構造方法: * Socket(String host, int port) 傳遞服務器IP和端口號 * 注意:構造方法只要運行,就會和服務器進行鏈接,鏈接失敗,拋出異常 * * OutputStream getOutputStream() 返回套接字的輸出流 * 做用: 將數據輸出,輸出到服務器 * * InputStream getInputStream() 返回套接字的輸入流 * 做用: 從服務器端讀取數據 * * 客戶端服務器數據交換,必須使用套接字對象Socket中的獲取的IO流,本身new流,不行 */ public class TCPClient { public static void main(String[] args)throws IOException { //建立Socket對象,鏈接服務器 Socket socket = new Socket("127.0.0.1", 8888); //經過客戶端的套接字對象Socket方法,獲取字節輸出流,將數據寫向服務器 OutputStream out = socket.getOutputStream(); out.write("服務器OK".getBytes()); //讀取服務器發回的數據,使用socket套接字對象中的字節輸入流 InputStream in = socket.getInputStream(); byte[] data = new byte[1024]; int len = in.read(data); System.out.println(new String(data,0,len)); socket.close(); } } /* * 實現TCP服務器程序 * 表示服務器程序的類 java.net.ServerSocket * 構造方法: * ServerSocket(int port) 傳遞端口號 * * 很重要的事情: 必需要得到客戶端的套接字對象Socket * Socket accept() */ public class TCPServer { public static void main(String[] args) throws IOException{ ServerSocket server = new ServerSocket(8888); //調用服務器套接字對象中的方法accept() 獲取客戶端套接字對象 Socket socket = server.accept(); //經過客戶端套接字對象,socket獲取字節輸入流,讀取的是客戶端發送來的數據 InputStream in = socket.getInputStream(); byte[] data = new byte[1024]; int len = in.read(data); System.out.println(new String(data,0,len)); //服務器向客戶端回數據,字節輸出流,經過客戶端套接字對象獲取字節輸出流 OutputStream out = socket.getOutputStream(); out.write("收到,謝謝".getBytes()); socket.close(); server.close(); } }
*A TCP上傳客戶端 /* * 實現TCP圖片上傳客戶端 * 實現步驟: * 1. Socket套接字鏈接服務器 * 2. 經過Socket獲取字節輸出流,寫圖片 * 3. 使用本身的流對象,讀取圖片數據源 * FileInputStream * 4. 讀取圖片,使用字節輸出流,將圖片寫到服務器 * 採用字節數組進行緩衝 * 5. 經過Socket套接字獲取字節輸入流 * 讀取服務器發回來的上傳成功 * 6. 關閉資源 */ public class TCPClient { public static void main(String[] args) throws IOException{ Socket socket = new Socket("127.0.0.1", 8000); //獲取字節輸出流,圖片寫到服務器 OutputStream out = socket.getOutputStream(); //建立字節輸入流,讀取本機上的數據源圖片 FileInputStream fis = new FileInputStream("c:\\t.jpg"); //開始讀寫字節數組 int len = 0 ; byte[] bytes = new byte[1024]; while((len = fis.read(bytes))!=-1){ out.write(bytes, 0, len); } //給服務器寫終止序列 //socket.shutdownOutput(); //獲取字節輸入流,讀取服務器的上傳成功 InputStream in = socket.getInputStream(); len = in.read(bytes); System.out.println(new String(bytes,0,len)); fis.close(); socket.close(); } }
A:TCP上傳服務器 /* * TCP圖片上傳服務器 * 1. ServerSocket套接字對象,監聽端口8000 * 2. 方法accept()獲取客戶端的鏈接對象 * 3. 客戶端鏈接對象獲取字節輸入流,讀取客戶端發送圖片 * 4. 建立File對象,綁定上傳文件夾 * 判斷文件夾存在, 不存,在建立文件夾 * 5. 建立字節輸出流,數據目的File對象所在文件夾 * 6. 字節流讀取圖片,字節流將圖片寫入到目的文件夾中 * 7. 將上傳成功會寫客戶端 * 8. 關閉資源 * */ public class TCPServer { public static void main(String[] args) throws IOException{ ServerSocket server = new ServerSocket(8000); Socket socket = server.accept(); //經過客戶端鏈接對象,獲取字節輸入流,讀取客戶端圖片 InputStream in = socket.getInputStream(); //將目的文件夾封裝到File對象 File upload = new File("d:\\upload"); if(!upload.exists()) upload.mkdirs(); //建立字節輸出流,將圖片寫入到目的文件夾中 FileOutputStream fos = new FileOutputStream(upload+"t.jpg"); //讀寫字節數組 byte[] bytes = new byte[1024]; int len = 0 ; while((len = in.read(bytes))!=-1){ fos.write(bytes, 0, len); } //經過客戶端鏈接對象獲取字節輸出流 //上傳成功寫回客戶端 socket.getOutputStream().write("上傳成功".getBytes()); fos.close(); socket.close(); server.close(); } }
/* * 實現TCP圖片上傳客戶端 * 實現步驟: * 1. Socket套接字鏈接服務器 * 2. 經過Socket獲取字節輸出流,寫圖片 * 3. 使用本身的流對象,讀取圖片數據源 * FileInputStream * 4. 讀取圖片,使用字節輸出流,將圖片寫到服務器 * 採用字節數組進行緩衝 * 5. 經過Socket套接字獲取字節輸入流 * 讀取服務器發回來的上傳成功 * 6. 關閉資源 */ public class TCPClient { public static void main(String[] args) throws IOException{ Socket socket = new Socket("127.0.0.1", 8000); //獲取字節輸出流,圖片寫到服務器 OutputStream out = socket.getOutputStream(); //建立字節輸入流,讀取本機上的數據源圖片 FileInputStream fis = new FileInputStream("c:\\t.jpg"); //開始讀寫字節數組 int len = 0 ; byte[] bytes = new byte[1024]; while((len = fis.read(bytes))!=-1){ out.write(bytes, 0, len); } //給服務器寫終止序列 socket.shutdownOutput();//想服務端寫入一個結束標誌 //獲取字節輸入流,讀取服務器的上傳成功 InputStream in = socket.getInputStream(); len = in.read(bytes); System.out.println(new String(bytes,0,len)); fis.close(); socket.close(); } }
*A:TCP上傳文件名 /* * TCP圖片上傳服務器 * 1. ServerSocket套接字對象,監聽端口8000 * 2. 方法accept()獲取客戶端的鏈接對象 * 3. 客戶端鏈接對象獲取字節輸入流,讀取客戶端發送圖片 * 4. 建立File對象,綁定上傳文件夾 * 判斷文件夾存在, 不存,在建立文件夾 * 5. 建立字節輸出流,數據目的File對象所在文件夾 * 6. 字節流讀取圖片,字節流將圖片寫入到目的文件夾中 * 7. 將上傳成功會寫客戶端 * 8. 關閉資源 * */ public class TCPServer { public static void main(String[] args) throws IOException{ ServerSocket server = new ServerSocket(8000); Socket socket = server.accept(); //經過客戶端鏈接對象,獲取字節輸入流,讀取客戶端圖片 InputStream in = socket.getInputStream(); //將目的文件夾封裝到File對象 File upload = new File("d:\\upload"); if(!upload.exists()) upload.mkdirs(); //防止文件同名被覆蓋,重新定義文件名字 //規則: 域名+毫秒值+6位隨機數 String filename="itcast"+System.currentTimeMillis()+new Random().nextInt(999999)+".jpg"; //建立字節輸出流,將圖片寫入到目的文件夾中 FileOutputStream fos = new FileOutputStream(upload+File.separator+filename); //讀寫字節數組 byte[] bytes = new byte[1024]; int len = 0 ; while((len = in.read(bytes))!=-1){ fos.write(bytes, 0, len); } //經過客戶端鏈接對象獲取字節輸出流 //上傳成功寫回客戶端 socket.getOutputStream().write("上傳成功".getBytes()); fos.close(); socket.close(); server.close(); } }
*A:多線程上傳案例 public class TCPThreadServer { public static void main(String[] args) throws IOException { ServerSocket server = new ServerSocket(8000); while (true) { // 獲取到一個客戶端,必須開啓新線程,爲這個客戶端服務 Socket socket = server.accept(); new Thread(new Upload(socket)).start(); } } } public class Upload implements Runnable { private Socket socket; public Upload(Socket socket) { this.socket = socket; } public void run() { try { // 經過客戶端鏈接對象,獲取字節輸入流,讀取客戶端圖片 InputStream in = socket.getInputStream(); // 將目的文件夾封裝到File對象 File upload = new File("d:\\upload"); if (!upload.exists()) upload.mkdirs(); // 防止文件同名被覆蓋,重新定義文件名字 // 規則: 域名+毫秒值+6位隨機數 String filename = "itcast" + System.currentTimeMillis() + new Random().nextInt(999999) + ".jpg"; // 建立字節輸出流,將圖片寫入到目的文件夾中 FileOutputStream fos = new FileOutputStream(upload + File.separator + filename); // 讀寫字節數組 byte[] bytes = new byte[1024]; int len = 0; while ((len = in.read(bytes)) != -1) { fos.write(bytes, 0, len); } // 經過客戶端鏈接對象獲取字節輸出流 // 上傳成功寫回客戶端 socket.getOutputStream().write("上傳成功".getBytes()); fos.close(); socket.close(); } catch (Exception ex) { } } }