【Java】网络编程
1 通信協議
通信的協議還是比較復雜的, java.net 包中包含的類和接口,它們提供低層次的通信細節。我們可以直接使用這些類和接口,來專注于網絡程序開發,而不用考慮通信的細節。
java.net 包中提供了兩種常見的網絡協議的支持:tcp和udp
TCP:傳輸控制協議 (Transmission Control Protocol)。TCP協議是面向連接的通信協議,即傳輸數據之前,在發送端和接收端建立邏輯連接,然后再傳輸數據,它提供了兩臺計算機之間可靠無差錯的數據傳輸。
三次握手:TCP協議中,在發送數據的準備階段,客戶端與服務器之間的三次交互,以保證連接的可靠。
第一次握手,客戶端向服務器端發出連接請求,等待服務器確認。
第二次握手,服務器端向客戶端回送一個響應,通知客戶端收到了連接請求。
第三次握手,客戶端再次向服務器端發送確認信息,確認連接。整個交互過程如下圖所示。
UDP:用戶數據報協議(User Datagram Protocol)。UDP協議是一個面向無連接的協議。傳輸數據時,不需要建立連接,不管對方端服務是否啟動,直接將數據、數據源和目的地都封裝在數據包中,直接發送。每個數據包的大小限制在64k以內。它是不可靠協議,因為無連接,所以傳輸速度快,但是容易丟失數據。日常應用中,例如視頻會議、QQ聊天等。耗資小效率高,容易丟數據
2 網絡編程三要素
協議:計算機網絡通信必須遵守的規則。
IP地址:指互聯網協議地址(Internet Protocol Address),俗稱IP。IP地址用來給一個網絡中的計算機設備做唯一的編號。假如我們把“個人電腦”比作“一臺電話”的話,那么“IP地址”就相當于“電話號碼”。
IP地址分類
- IPv4:是一個32位的二進制數,通常被分為4個字節,表示成a.b.c.d 的形式,例如192.168.65.100 。其中a、b、c、d都是0~255之間的十進制整數,那么最多可以表示42億個。
- IPv6:由于互聯網的蓬勃發展,IP地址的需求量愈來愈大,但是網絡地址資源有限,使得IP的分配越發緊張。有資料顯示,全球IPv4地址在2011年2月分配完畢。為了擴大地址空間,擬通過IPv6重新定義地址空間,采用128位地址長度,每16個字節一組,分成8組十六進制數,表示成ABCD:EF01:2345:6789:ABCD:EF01:2345:6789 ,號稱可以為全世界的每一粒沙子編上一個網址,這樣就解決了網絡地址資源數量不夠的問題。
常用命令
查看本機IP地址,在控制臺輸入:ipconfig
檢查網絡是否連通,在控制臺輸入:ping ip地址
特殊的IP地址:本機IP地址: 127.0.0.1 、localhost 。
端口號
網絡的通信,本質上是兩個進程(應用程序)的通信。每臺計算機都有很多的進程,那么在網絡通信時,如何區分這些進程呢?如果說IP地址可以唯一標識網絡中的設備,那么端口號就可以唯一標識設備中的進程(應用程序)了。
端口號:用兩個字節表示的整數,它的取值范圍是0~65535。其中,0~1023之間的端口號用于一些知名的網絡服務和應用,普通的應用程序需要使用1024以上的端口號。如果端口號被另外一個服務或應用所占用,會導致當前程序啟動失敗。
利用協議+ IP地址+ 端口號 三元組合,就可以標識網絡中的進程了,那么進程間的通信就可以利用這個標識與其它進程進行交互。
常用端口號:
- 80端口 網絡端口
- 數據庫端口 mysql:3306 oracle:1521
- tomcat端口:8080
3 TCP通信程序
TCP通信能實現兩臺計算機之間的數據交互,通信的兩端要嚴格區分客戶端和服務端
通信步驟
服務端要做的事:
3.1 TCP客戶端代碼實現
構造方法:Socket(String host, int port)
成員方法:
- OutputStream getOutputStream():返回輸出流
- InputStream getInputStream():返回輸入流
- void close():關閉套接字
實現步驟:
3.2 TCP服務端代碼實現
構造方法:Socket(int port):創建綁定到特定端口的服務器套接字
成員方法:
- Socket accept():偵聽并接收到此套接字連接
實現步驟:
3.3 練習1-文件上傳
原理:客戶端讀取本地的文件,把文件上傳到服務器,服務器把上傳的文件保存到服務器的硬盤上。
步驟
本地硬盤讀寫用本地字節流,CS間通信用網絡字節流
客戶端實現
服務端實現
注意上傳阻塞問題
fis.read 讀取本地文件 結束標記是讀取到-1
while循環不會讀取-1 也不會寫給服務器
read讀不到-1 進入死循環
解決方法:上傳結束后,寫一個結束標記。使用socket.shutdown()
3.4 練習2-文件上傳優化版
3.5 BS服務器實現
使用FileInputStream創建對象的時候遇到了問題,相對路徑訪問不了,這個問題暫時還不知道怎么解決,所以強行把父路徑加上了,訪問絕對路徑就沒問題。
import java.io.*; import java.net.ServerSocket; import java.net.Socket;/*創建BS版本TCP服務器*/ public class TCPServerThread {public static void main(String[] args) throws IOException {//創建一個服務器ServerSocket,和系統要指定的端口號ServerSocket server = new ServerSocket(8080);/*瀏覽器解析服務器回寫的html頁面,頁面中如果有圖片,那么瀏覽器就會單獨的開啟一個線程,讀取服務器的圖片我們就的讓服務器一直處于監聽狀態,客戶端請求一次,服務器就回寫一次*/while(true){//使用accept方法獲取到請求的客戶端對象(瀏覽器)Socket socket = server.accept();new Thread(new Runnable() {@Overridepublic void run() {try {//使用Socket對象中的方法getInputStream,獲取到網絡字節輸入流InputStream對象InputStream is = socket.getInputStream();//把is網絡字節輸入流對象,轉換為字符緩沖輸入流BufferedReader br = new BufferedReader(new InputStreamReader(is));//把客戶端請求信息的第一行讀取出來 GET /11_Net/web/index.html HTTP/1.1String line = br.readLine();System.out.println(line);//把讀取的信息進行切割,只要中間部分 /11_Net/web/index.htmlString[] arr = line.split(" ");//把路徑前邊的/去掉,進行截取 11_Net/web/index.htmlString htmlpath = arr[1].substring(1);//使用FileInputStream創建對象的時候遇到了問題//相對路徑訪問不了 不知道怎么解決//所以強行把父路徑加上了//訪問絕對路徑就沒問題File file = new File("").getAbsoluteFile();htmlpath = file.getParent() + "\\" + htmlpath;//創建一個本地字節輸入流,構造方法中綁定要讀取的html路徑FileInputStream fis = new FileInputStream(htmlpath);//使用Socket中的方法getOutputStream獲取網絡字節輸出流OutputStream對象OutputStream os = socket.getOutputStream();// 寫入HTTP協議響應頭,固定寫法os.write("HTTP/1.1 200 OK\r\n".getBytes());os.write("Content-Type:text/html\r\n".getBytes());// 必須要寫入空行,否則瀏覽器不解析os.write("\r\n".getBytes());//一讀一寫復制文件,把服務讀取的html文件回寫到客戶端int len = 0;byte[] bytes = new byte[1024];while((len = fis.read(bytes))!=-1){os.write(bytes,0,len);}//釋放資源fis.close();socket.close();}catch (IOException e){e.printStackTrace();}}}).start();}//server.close();} }總結
以上是生活随笔為你收集整理的【Java】网络编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python学习练习:批量移动文件
- 下一篇: Windows10 virtualbox