day14_面向對象(網絡編程)
一.網絡編程對象入門
1.軟件架構介紹
CS架構:Client/Server 客戶端/服務器
比如:QQ,迅雷,淘寶,京東
BS架構:Browser/Server 瀏覽器/服務器
比如:淘寶網,京東網
(BS慢慢會取代CS,方便)
2.網絡通信協議介紹
網絡通信協議:互聯網上的計算機之間進行數據交互,需要遵循的規則
交通管理條例(類比)
3.常用的通信協議
TCP/IP協議
IP協議:互聯網協議
注意規定就是計算的IP地址相關內容
TCP協議(傳輸控制協議):
特點:面向有鏈接(通過三次握手建立連接)
能保證數據的完整性和安全性,性能較低
(應用:客戶端下載)
UDP協議(用戶數據報協議):
特點:面向無連接(發數據之前不需要建立連接,甚至不需要關心對象是否存在)
不能保證數據完整性和安全性,性能很高
(應用:視頻通話,屏幕共享)
4.網絡編程的三要素
a.各種網絡協議
b.IP地址
IP地址是每一臺聯網的計算機的唯一標識
IPv4地址:由32位二進制組成。4個字節,一共有42億種
127 . 128 . 234 . 222
一個字節的取值範圍:0~255
c.端口號
是一臺計算機上不同軟件的標識,一共有0~65535個端口號。我們在寫程序時,建議使用1024以上端口號
用兩個字節表示的整數,它的取值範圍是0~65535。其中,0~1023之間的端口號用於一些知名的網絡服務和應用,普通的應用程序需要使用1024以上的端口號。如果端口號被另外一個服務或應用所佔用,會導致當前程序啓動失敗。
擴展:
a.IP地址的未來
IPv4版本:32位組成,只能標識42億種IP(面臨枯竭)
IPv6版本:128位組成,號稱可以爲全球的每一粒沙子起一個IP地址,且不重複
b.IP地址的獲取和測試(Dos命令)
查看本機IP命令:ipconfig(查看以太網IP地址)
檢查網絡是否通暢:ping 對方的IP
c.特殊的IP地址
127.0.0.1 本機迴環地址(測試用的)
二.TCP通信
1.TCP通信分爲客戶端和服務器
客戶端:個人電腦,手機
服務器:公司大型電腦 1P =1024T 1E = 1024P
2.TCP中的兩個重要的類
代表客戶端:Socket(套接字)
代表服務器:ServerSocket(服務器套接字)
3.Socket類的介紹和使用
a.構造方法
public Socket(String ip, int port);此構造的底層會自動連接服務器(三次握手)
如果連接成功,那麼該客戶端對象成功創建
如果連接失敗,直接拋出異常
b.常用方法
public OutputStream getOutputStream(); 獲取通道輸出流
public InputStream getInputStream(); 獲取通道的輸入流
public void shutDownOutput(); 關閉通道中的輸出流
public void shutDownInput(); 關閉通道中的輸入流
public void close(); 關閉客戶端對象 4.ServerSocket類的介紹和使用
a.構造方法:
public ServerSocket(int port); 創建服務器,並指定服務器所在的端口號
b.常用的成員方法
public void close(); 關閉服務器對象
public Socket accept(); 接收連接到服務器的那個客戶端對象
5.簡單的TCP通信實現(單向實現)***************
public class TCPClient {
public static void main(String[] args) throws IOException {
//1.創建客戶端對象
Socket client = new Socket("127.0.0.1",54321);
System.out.println("客戶端成功連接到服務器...");
//2.獲取通道中的輸出流
OutputStream out = client.getOutputStream();
//3.調用out的寫數據方法
out.write("你好服務器,我是你大爺...".getBytes());
System.out.println("數據發送成功...");
//4.釋放資源
out.close();
client.close();
System.out.println("客戶端成功關閉...");
}
}
public class TCPServer {
public static void main(String[] args) throws IOException {
//1.創建服務器對象
ServerSocket server = new ServerSocket(54321);
System.out.println("服務器成功啓動...");
//2.接收客戶端對象
System.out.println("等待客戶端的連接...");
Socket client = server.accept();//accept方法具體阻塞功能
System.out.println("有客戶端來了...");
//3.獲取通道中的輸入流
InputStream in = client.getInputStream();
//4.調用in的讀數據方法
byte[] bs = new byte[1024];
int len = in.read(bs);
System.out.println("客戶端發送消息:"+new String(bs,0,len));
//5.釋放資源
in.close();
client.close();
server.close();
System.out.println("服務器成功關閉...");
}
}
6.簡單的TCP通信實現(雙向實現)
單向通信:
客戶端連接到服務器後,給服務器發送信息,然後關閉
服務器獲取到客戶端連接後,讀取客戶端的信息,然後關閉
雙向通信:
客戶端連接到服務器後,給服務器發送信息,等待服務器回的信息,讀取後再關閉
服務器獲取到客戶端連接後,讀取客戶端的信息,然後給客戶端回信息,再關閉
public class TCPClient {
public static void main(String[] args) throws IOException {
//1.創建客戶端對象
Socket client = new Socket("127.0.0.1", 54321);
System.out.println("客戶端成功連接到服務器...");
//2.獲取通道中的輸出流
OutputStream out = client.getOutputStream();
//3.調用out的寫數據方法
out.write("你好服務器,我是你大爺...".getBytes());
System.out.println("數據發送成功...");
//======雙向通信,不要立刻關閉,而要讀取服務器回的信息======
//4.獲取通道中的輸入流
InputStream in = client.getInputStream();
//5.從流中讀取服務器回的信息
byte[] bs = new byte[1024];
int len = in.read(bs);
System.out.println("服務器回信息:" + new String(bs, 0, len));
//6.釋放資源
out.close();
client.close();
System.out.println("客戶端成功關閉...");
}
}
public class TCPServer {
public static void main(String[] args) throws IOException {
//1.創建服務器對象
ServerSocket server = new ServerSocket(54321);
System.out.println("服務器成功啓動...");
//2.接收客戶端對象
System.out.println("等待客戶端的連接...");
Socket client = server.accept();//accept方法具體阻塞功能
System.out.println("有客戶端來了...");
//3.獲取通道中的輸入流
InputStream in = client.getInputStream();
//4.調用in的讀數據方法
byte[] bs = new byte[1024];
int len = in.read(bs);
System.out.println("客戶端發送消息:"+new String(bs,0,len));
//========雙向通信,不要立刻關閉,而要給客戶端回信息==========
//5.獲取通道中的輸出流
OutputStream out = client.getOutputStream();
//6.向客戶端回信息
out.write("您的信息已經收到,您可以安息了...".getBytes());
System.out.println("已經成功給客戶端回信息了...");
//=======雙向通信,不要立刻關閉,而要給客戶端回信息===========
//7.釋放資源
out.close();
in.close();
client.close();
server.close();
System.out.println("服務器成功關閉...");
}
}
三.綜合案例:文件上傳
1.文件上傳案例分析(畫圖分析)
2.文件上傳案例實現(代碼演示)
/**
* TCP文件上傳的客戶端
*/
public class TCPFileUploadClient {
public static void main(String[] args) throws IOException {
// 1.創建客戶端對象
Socket client = new Socket("127.0.0.1",11111);
System.out.println("連接服務器成功...");
// 2.獲取通道中的輸出流
OutputStream out = client.getOutputStream();
// 3.創建文件的字節輸入流
FileInputStream fis = new FileInputStream("1.png");
// 循環:一邊從文件中讀取對象,一邊通過輸出流發送給服務器
System.out.println("正在發送文件....");
byte[] bs = new byte[1024];
int len = 0;
while ((len = fis.read(bs))!=-1) {
//發送服務器
out.write(bs, 0, len);
}
//當客戶端文件發送完畢,一定要告知服務器
//解決方案;把輸出流關閉
client.shutdownOutput();
System.out.println("發送發送完畢....");
// 4.獲取通道中的輸入流(讀取服務器的反饋信息)
InputStream in = client.getInputStream();
byte[] bs1 = new byte[1024];
int len1 = in.read(bs1);
System.out.println("服務器說:" + new String(bs1, 0, len1));
// 5.釋放資源
in.close();
fis.close();
out.close();
client.close();
System.out.println("客戶端成功關閉...");
}
}
public class TCPFileUploadServer {
public static void main(String[] args) throws IOException {
// 1.創建服務器對象
ServerSocket server = new ServerSocket(11111);
System.out.println("服務器啓動成功...");
// 2.接收客戶端對象
System.out.println("等待客戶端連接...");
Socket client = server.accept();
System.out.println("有客戶端連接了,"+client.getInetAddress().getHostAddress());
// 3.獲取通道中的輸入流
InputStream in = client.getInputStream();
// 4.創建文件的字節輸出流
String filename = "G:\\uploads\\1.png";
FileOutputStream fos = new FileOutputStream(filename);
// 循環:一邊從輸入流中讀數據,一邊寫到文件中
System.out.println("正在接收客戶端發送的文件..");
byte[] bs = new byte[1024];
int len = 0;
while ((len = in.read(bs)) != -1) {
//寫到文件中
fos.write(bs, 0, len);
}
System.out.println("服務器接收文件完畢...");
// 5.獲取通道中的輸出流(向客戶端發送反饋信息)
OutputStream out = client.getOutputStream();
out.write(("您的文件收到了,保存到服務器:"+filename).getBytes());
System.out.println("給客戶端發送反饋完畢...");
// 6.釋放資源
out.close();
fos.close();
in.close();
client.close();
server.close();
System.out.println("服務器關閉成功...");
}
}
3.文件中上傳案例實現的不足之處
a.服務器保存文件時,由於文件名固定,導致只有一個文件
b.每次啓動服務器只能服務一個客戶端
c.如果客戶端的數據過多,導致和該客戶端的交互時間太長,無法接受下一個客戶端
4.文件上傳案例的優化實現(代碼演示)
public class TCPFileUploadServer {
public static void main(String[] args) throws IOException {
// 1.創建服務器對象
ServerSocket server = new ServerSocket(11111);
System.out.println("服務器啓動成功...");
while (true) {
// 2.接收客戶端對象
System.out.println("等待客戶端連接...");
Socket client = server.accept();
System.out.println("有客戶端連接了," + client.getInetAddress().getHostAddress());
//創建一個線程
new Thread(new Runnable() {
@Override
public void run() {
//任務
try {
// 3.獲取通道中的輸入流
InputStream in = client.getInputStream();
// 4.創建文件的字節輸出流
String filename = "G:\\uploads\\" + System.currentTimeMillis() + new Random().nextInt(100) + ".png";
FileOutputStream fos = new FileOutputStream(filename);
// 循環:一邊從輸入流中讀數據,一邊寫到文件中
System.out.println("正在接收客戶端發送的文件..");
byte[] bs = new byte[1024];
int len = 0;
while ((len = in.read(bs)) != -1) {
//寫到文件中
fos.write(bs, 0, len);
}
System.out.println("服務器接收文件完畢...");
// 5.獲取通道中的輸出流(向客戶端發送反饋信息)
OutputStream out = client.getOutputStream();
out.write(("您的文件收到了,保存到服務器:" + filename).getBytes());
System.out.println("給客戶端發送反饋完畢...");
// 6.釋放資源
out.close();
fos.close();
in.close();
client.close();
} catch (IOException ie) {
ie.printStackTrace();
}
}
}).start();
}
// server.close();
// System.out.println("服務器關閉成功...");
}
}
5.模擬BS架構服務器
6.擴展:模擬服務器擴展——圖片顯示問題
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class BSServer {
public static void main(String[] args) throws IOException {
//1.創建服務器對象
ServerSocket server = new ServerSocket(8888);
while (true){
//2.接收客戶端對象
Socket socket = server.accept();
System.out.println("有客戶端連接了,"+socket.getInetAddress().getHostAddress());
new Thread(new Web(socket)).start();
}
}
}
class Web implements Runnable{
private Socket socket;
public Web(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try{
//3.獲取通道中的輸入流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//4.讀取數據
String line = null;
//5.只需要讀取一行
line = br.readLine(); //GET /1.html HTTP/1.1
String[] names = line.split(" ");
String filename = names[1].substring(1);
System.out.println(filename);
//通過文件的輸入流讀取文件
FileInputStream fis = new FileInputStream(filename);
// System.out.println(br.readLine());
// while ((line = br.readLine())!=null){
// System.out.println(line);
// }
// 通過通道中的輸出流把文件發送給瀏覽器
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());
//循環
byte[] b = new byte[1024];
int len1 = 0;
while ((len1 = fis.read(b))!=-1){
out.write(b,0,len1);
}
//6.釋放資源
out.close();
fis.close();
br.close();
socket.close();
}catch(IOException ie){
ie.printStackTrace();
}
}
}
總結:
-[] 能夠辨別UDP和TCP協議特點
-[] 能夠說出TCP協議下兩個常用類名稱
Socket
ServerSocket
-[] 能夠編寫TCP協議下字符串數據傳輸程序****************
-[] 能夠理解TCP協議下文件上傳案例
-[] 能夠理解TCP協議下模擬B\S服務器案例