經過計算機網絡可使多臺計算機實現鏈接,位於同一個網絡中的計算機在進行鏈接和通訊時須要遵照必定的規則數組
1.計算機指定一個標識號,經過這個標識號來指定接受數據的計算機或者發送數據的計算機。服務器
2.IPv4,它是由4個字節大小的二進制數來表示,如:00001010000000000000000000000001。因爲二進制形式表示的IP地址很是不便記憶和處理,所以一般會將IP地址寫成十進制的形式,每一個字節用一個十進制數字(0-255)表示,數字間用符號「.」分開,如 「192.168.1.100」。網絡
3.IPv6使用16個字節表示IP地址,它所擁有的地址容量約是IPv4的8×1028倍,達到2128個(算上全零的),這樣就解決了網絡地址資源數量不夠的問題。oracle
4.訪問目標計算機中的某個應用程序,還須要指定端口號。在計算機中,不一樣的應用程序是經過端口號區分的。端口號是用兩個字節(16位的二進制數)表示的,它的取值範圍是0~65535,其中,0~1023之間的端口號用於一些知名的網絡服務和應用,用戶的普通應用程序須要使用1024以上的端口號,從而避免端口號被另一個應用或服務所佔用。dom
public class Demo01 { public static void main(String[] args) throws UnknownHostException { //獲取本地主機對象 InetAddress inet=InetAddress.getLocalHost(); System.out.println(inet); //根據主機名獲取Inet對象 InetAddress inet2=InetAddress.getByName("PC-201704301608"); System.out.println(inet2); //獲取主機名 System.out.println(inet2.getHostName()); //獲取ip地址 String ip=inet.getHostAddress(); System.out.println(ip); } }
2.1 UDP是無鏈接通訊協議,即在數據傳輸時,數據的發送端和接收端不創建邏輯鏈接。socket
UDP傳輸數據被限制在64K之內。this
2.2 TCP協議是面向鏈接的通訊協議,即在傳輸數據前先在發送端和接收端創建邏輯鏈接,而後再傳輸數據,它提供了兩臺計算機之間可靠無差錯的數據傳輸。spa
「三次握手」:第一次握手,客戶端向服務器端發出鏈接請求,等待服務器確認,第二次握手,服務器端向客戶端回送一個響應,通知客戶端收到了鏈接請求,第三次握手,客戶端再次向服務器端發送確認信息,確認鏈接。計算機網絡
JDK中提供了一個DatagramPacket類,該類的實例對象就至關於一個集裝箱,用於封裝UDP通訊中發送或者接收的數據。線程
在建立發送端和接收端的DatagramPacket對象時,使用的構造方法有所不一樣,接收端的構造方法只須要接收一個字節數組來存放接收到的數據,而發送端的構造方法不但要接收存放了發送數據的字節數組,還須要指定發送端IP地址和端口號。
JDK中提供的一個DatagramSocket類。DatagramSocket類的做用就相似於碼頭,使用這個類的實例對象就能夠發送和接收DatagramPacket數據包。
發送端:
public class UDPSend { //UDP協議發送端 public static void main(String[] args) throws IOException { Scanner sc=new Scanner(System.in); String str=sc.next(); //1.建立數據包對象,封裝要發送的信息,接收端的ip以及端口號 byte[]bytes=str.getBytes(); InetAddress inet=InetAddress.getByName("127.0.0.1"); DatagramPacket dp=new DatagramPacket(bytes, bytes.length,inet,8888); //2.建立DatagramSocket對象 DatagramSocket ds=new DatagramSocket(); //3.發送數據包 ds.send(dp); //4.釋放資源 ds.close(); } }
接受端:
public class UDPRecieve { //UDP接收端 public static void main(String[] args) throws IOException { //1.建立DatagramSocket對象明確端口號 DatagramSocket ds=new DatagramSocket(8888); //2.建立字節數組接受數據 byte[]bytes=new byte[1024]; //3.建立數據包對象 DatagramPacket dp=new DatagramPacket(bytes, bytes.length); //4.接受數據包 ds.receive(dp); //5.拆包 //獲取發送端的ip地址 String ip=dp.getAddress().getHostAddress(); //獲取發送端的端口號 int port=dp.getPort(); //獲取實際數據的長度 int length=dp.getLength(); System.out.println("ip地址爲"+ip+",端口號爲"+port+"發送的內容爲:"+new String(bytes,0,length)); System.out.println(new String(bytes)); //6.關閉資源 } }
在JDK中提供了兩個類用於實現TCP程序,一個是ServerSocket類,用於表示服務器端,一個是Socket類,用於表示客戶端。
經過一張圖來描述服務器端和客戶端的數據傳輸,以下圖所示。
服務器端:
public class TCPServer { public static void main(String[] args) throws IOException { //建立ServerSocket對象,接受客戶端 ServerSocket server=new ServerSocket(8888); //調用accept方法,獲取鏈接個人客戶端的Socket對象 Socket socket=server.accept(); //獲取輸入字節流 InputStream in=socket.getInputStream(); byte[]bytes=new byte[1024]; int len=in.read(bytes); //獲取ip地址 String ip=socket.getLocalAddress().getHostAddress(); //獲取端口號 int port=socket.getPort(); System.out.println(ip+port+new String(bytes,0,len)); //回覆客戶端 OutputStream out=socket.getOutputStream(); out.write("收到!".getBytes()); //釋放資源 server.close(); } }
客戶端:
public class TCPClient { public static void main(String[] args) throws IOException { // 建立Socket對象,鏈接服務器 Socket socket = new Socket("127.0.0.1", 8888); // 獲取字節輸出流 OutputStream out = socket.getOutputStream(); // 發送數據 out.write("你好服務器".getBytes()); // 接受服務器端的回覆 InputStream in = socket.getInputStream(); byte[] bytes = new byte[1024]; int len = in.read(bytes); // 獲取ip地址 String ip = socket.getLocalAddress().getHostAddress(); // 獲取端口號 int port = socket.getPort(); System.out.println(ip + port + new String(bytes, 0, len)); // 釋放資源 socket.close(); } }
練習:文件上傳到服務器
線程接口:
public class MyRunnable implements Runnable { private Socket socket; public MyRunnable(Socket socket) { this.socket = socket; } public void run() { FileOutputStream fos = null; try { // 獲取字節輸入流 InputStream in = socket.getInputStream(); // 明確目的地 File file = new File("D:\\upload"); // 若是文件夾不存在,則建立一個新的文件夾 if (!file.exists()) { file.mkdirs(); } // 文件路徑 // 文件名:域名+毫秒值+6位隨機數 String filename = "oracle" + System.currentTimeMillis() + new Random().nextInt(999999); String path = file.getAbsolutePath() + File.separator + filename + ".png"; fos = new FileOutputStream(path); // 開始複製 byte[] bytes = new byte[1024]; int len = 0; while ((len = in.read(bytes)) != -1) { fos.write(bytes, 0, len); } // 回覆客戶端 OutputStream out = socket.getOutputStream(); out.write("上傳成功!".getBytes()); } catch (IOException ex) { ex.printStackTrace(); } finally { // 釋放資源 try { fos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
服務器端:
public class TCPServer { public static void main(String[] args) throws IOException { // 建立ServerSocket對象,接受客戶端 ServerSocket server = new ServerSocket(8888); while (true) { // 調用accept方法,建立鏈接並獲取客戶端Socket對象 Socket socket = server.accept(); MyRunnable mr = new MyRunnable(socket); new Thread(mr).start(); } } }
客戶端:
public class TCPClient { public static void main(String[] args) throws UnknownHostException, IOException { //建立Socket對象,鏈接服務器 Socket socket=new Socket("192.168.1.171",8888); //獲取字節輸出流 OutputStream out=socket.getOutputStream(); //建立字節輸入流,明確數據源 FileInputStream fis=new FileInputStream("D:\\test\\a1.jpg"); byte[]bytes=new byte[1024]; //開始複製 int len=0; 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(); } }