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