一、網絡編程入門
1.1 軟件結構
C/S結構 :全稱爲Client/Server結構,是指客戶端和服務器結構。常見程序有QQ、迅雷等軟件。
B/S結構 :全稱爲Browser/Server結構,是指瀏覽器和服務器結構。常見瀏覽器有谷歌、火狐等。
1.2 網絡通信協議
TCP/IP協議: 傳輸控制協議/因特網互聯協議( Transmission Control Protocol/Internet Protocol),是
Internet最基本、最廣泛的協議。它定義了計算機如何連入因特網,以及數據如何在它們之間傳輸的標準。它
的內部包含一系列的用於處理數據通信的協議,並採用了4層的分層模型,每一層都呼叫它的下一層所提供的
協議來完成自己的需求。
1.3 協議分類
通信的協議還是比較複雜的, java.net 包中包含的類和接口,它們提供低層次的通信細節。我們可以直接使用這
些類和接口,來專注於網絡程序開發,而不用考慮通信的細節。
java.net 包中提供了兩種常見的網絡協議的支持:
TCP:傳輸控制協議 (Transmission Control Protocol)。TCP協議是面向連接的通信協議,即傳輸數據之前,
在發送端和接收端建立邏輯連接,然後再傳輸數據,它提供了兩臺計算機之間可靠無差錯的數據傳輸。
三次握手:TCP協議中,在發送數據的準備階段,客戶端與服務器之間的三次交互,以保證連接的可
靠。
——第一次握手,客戶端向服務器端發出連接請求,等待服務器確認。
——第二次握手,服務器端向客戶端回送一個響應,通知客戶端收到了連接請求。
——第三次握手,客戶端再次向服務器端發送確認信息,確認連接。
UDP:用戶數據報協議(User Datagram Protocol)。UDP協議是一個面向無連接的協議。傳輸數據時,不需
要建立連接,不管對方端服務是否啓動,直接將數據、數據源和目的地都封裝在數據包中,直接發送。每個
數據包的大小限制在64k以內。它是不可靠協議,因爲無連接,所以傳輸速度快,但是容易丟失數據。日常應
用中,例如視頻會議、QQ聊天等。
1.4 網絡編程三要素
協議:計算機網絡通信必須遵守的規則。
IP地址: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地址
本機IP地址: 127.0.0.1 、 localhost 。
端口號
網絡的通信,本質上是兩個進程(應用程序)的通信。每臺計算機都有很多的進程,那麼在網絡通信時,如何區分這些進程呢?
如果說IP地址可以唯一標識網絡中的設備,那麼端口號就可以唯一標識設備中的進程(應用程序)了。
端口號:用兩個字節表示的整數,它的取值範圍是065535。其中,01023之間的端口號用於一些知名的網
絡服務和應用,普通的應用程序需要使用1024以上的端口號。如果端口號被另外一個服務或應用所佔用,會
導致當前程序啓動失敗。
利用 協議 + IP地址 + 端口號 三元組合,就可以標識網絡中的進程了,那麼進程間的通信就可以利用這個標識與其它進程進行交互。
二、TCP 通信程序
2.1 概述
TCP通信能實現兩臺計算機之間的數據交互,通信的兩端,要嚴格區分爲客戶端(Client)與服務端(Server)。
兩端通信時步驟:
- 服務端程序,需要事先啓動,等待客戶端的連接。
- 客戶端主動連接服務器端,連接成功才能通信。服務端不可以主動連接客戶端。
在Java中,提供了兩個類用於實現TCP通信程序: - 客戶端: java.net.Socket 類表示。創建 Socket 對象,向服務端發出連接請求,服務端響應請求,兩者建
立連接開始通信。 - 服務端: java.net.ServerSocket 類表示。創建 ServerSocket 對象,相當於開啓一個服務,並等待客戶端
的連接。
2.2 Socket類
Socket client = new Socket(“127.0.0.1”, 6666);
成員方法
public InputStream getInputStream() : 返回此套接字的輸入流。
-如果此Scoket具有相關聯的通道,則生成的InputStream 的所有操作也關聯該通道。
-關閉生成的InputStream也將關閉相關的Socket。
public OutputStream getOutputStream() : 返回此套接字的輸出流。
-如果此Scoket具有相關聯的通道,則生成的OutputStream 的所有操作也關聯該通道。
-關閉生成的OutputStream也將關閉相關的Socket。
public void close() :關閉此套接字。
-一旦一個socket被關閉,它不可再使用。
-關閉此socket也將關閉相關的InputStream和OutputStream 。
public void shutdownOutput() : 禁用此套接字的輸出流。
-任何先前寫出的數據將被髮送,隨後終止輸出流。
2.3 ServerSocket
創建:ServerSocket server = new ServerSocket(6666);
public Socket accept() :偵聽並接受連接,返回一個新的Socket對象,用於和客戶端實現通信。該方法
會一直阻塞直到建立連接。
2.4 簡單的TCP網絡程序
TCP通信分析圖解 - 【服務端】啓動,創建ServerSocket對象,等待連接。
Socket client = new Socket(“127.0.0.1”, 6666);
ServerSocket server = new ServerSocket(6666); - 【客戶端】啓動,創建Socket對象,請求連接。
- 【服務端】接收連接,調用accept方法,並返回一個Socket對象。
- 【客戶端】Socket對象,獲取OutputStream,向服務端寫出數據。
- 【服務端】Scoket對象,獲取InputStream,讀取客戶端發送的數據。
- 【服務端】Socket對象,獲取OutputStream,向客戶端回寫數據。
- 【客戶端】Scoket對象,獲取InputStream,解析回寫數據。
- 【客戶端】釋放資源,斷開連接。
三、綜合案例
3.1 文件上傳案例
客戶端:
package day11.DemoXXXX;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Socket_l {
public static void main(String[] args) throws Exception {
//創建
Socket socket = new Socket("127.0.0.1",8845);
//創建輸出給服務器的流
OutputStream os = socket.getOutputStream();
//獲取本地文件流
FileInputStream fis = new FileInputStream("D:\\課件\\就業班\\day07-13\\day10\\1.jpg");
//將讀取的文件傳送到服務器
byte[] bytes = new byte[1024*1024];
int len =0;
while ((len = fis.read(bytes))!=-1){
os.write(bytes,0,len);
os.flush();
}
socket.shutdownOutput();
//獲取服務器返回的信息
InputStream is = socket.getInputStream();
byte[] bytes1 = new byte[1024*1024];
int len1= 0;
while ((len1 = is.read(bytes1))!=-1){
System.out.println(bytes1);
}
//關閉客戶端
socket.close();
}
}
服務器端:
package day11.DemoXXXX;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
public class SS_P {
public static void main(String[] args) throws Exception {
//創建服務器
ServerSocket serverSocket = new ServerSocket(8845);
while (true){
new Thread(()->{
try {
//獲取客戶端的方法
Socket accept = serverSocket.accept();
//獲取信息,並保存
InputStream is = accept.getInputStream();
String FileName = System.currentTimeMillis()+ new Random().nextInt(99999)+".jpg";
FileOutputStream fos = new FileOutputStream("D:\\課件\\就業班\\day07-13\\day11\\code\\"+FileName);
byte[] bytes = new byte[1024*1024];
int len = 0;
while ((len = is.read(bytes))!=-1){
fos.write(bytes,0,len);
fos.flush();
}
//給服務器傳送信息
OutputStream os = accept.getOutputStream();
os.write("謝謝數據已收到".getBytes());
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
//接受客戶端傳送來的數據和保存數據的輸出流並保存
Random rd = new Random();
String FileName = System.currentTimeMillis()+rd.nextInt(99999)+".jpg";
FileOutputStream fos = new FileOutputStream("D:\\課件\\就業班\\day07-13\\day11\\avi\\"+FileName);
Socket accept = serverSocket.accept();
InputStream is = accept.getInputStream();
byte[] bytes = new byte[1024*1024];
int len = 0;
while((len = is.read(bytes))!=-1){
fos.write(bytes,0,len);
}
//給客戶端傳回數據
OutputStream os = accept.getOutputStream();
os.write("數據已收到。".getBytes());
//釋放資源
fos.flush();
fos.close();
}
}
}
四、模擬B/S服務
代碼實現:
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8888);
while(true){
Socket socket = server.accept();
new Thread(new Web(socket)).start();
}
}
static class Web implements Runnable{
private Socket socket;
public Web(Socket socket){
this.socket=socket;
}
public void run() {
try{
//轉換流,讀取瀏覽器請求第一行
BufferedReader readWb = new
BufferedReader(new InputStreamReader(socket.getInputStream()));
String requst = readWb.readLine();
//取出請求資源的路徑
String[] strArr = requst.split(" ");
System.out.println(Arrays.toString(strArr));
String path = strArr[1].substring(1);
System.out.println(path);
FileInputStream fis = new FileInputStream(path);
System.out.println(fis);
byte[] bytes= new byte[1024];
int len = 0 ;
//向瀏覽器 回寫數據
OutputStream out = socket.getOutputStream();
out.write("HTTP/1.1 200 OK\r\n".getBytes());
out.write("Content‐Type:text/html\r\n".getBytes());
out.write("\r\n".getBytes());
while((len = fis.read(bytes))!=‐1){
out.write(bytes,0,len);
}
fis.close();
out.close();
readWb.close();
socket.close();
}catch(Exception ex){
}
}
}
}