Java基礎進階_day17_(網絡編程)
1. 網絡編程
1.1 網絡編程三要素
網絡編程三要素:
A:IP地址
B:端口
C:協議
IP地址:
網絡中計算機的唯一標識。
計算機只能識別二進制的數據,所以我們的IP地址應該是一個二進制的數據。
但是呢,我們配置的IP地址確不是二進制的,爲什麼呢?
IP:192.168.1.100
換算:11000000 10101000 00000001 01100100
假如真是:11000000 10101000 00000001 01100100的話。
我們如果每次再上課的時候要配置該IP地址,記憶起來就比較的麻煩。
所以,爲了方便表示IP地址,我們就把IP地址的每一個字節上的數據換算成十進制,然後用.分開來表示:
"點分十進制"
IP地址的組成:網絡號段+主機號段
A類:第一號段爲網絡號段+後三段的主機號段
一個網絡號:256*256*256 = 16777216
B類:前二號段爲網絡號段+後二段的主機號段
一個網絡號:256*256 = 65536
C類:前三號段爲網絡號段+後一段的主機號段
一個網絡號:256
IP地址的分類:
A類 1.0.0.1---127.255.255.254 (1)10.X.X.X是私有地址(私有地址就是在互聯網上不使用,而被用在局域網絡中的地址) (2)127.X.X.X是保留地址,用做循環測試用的。
B類 128.0.0.1---191.255.255.254 172.16.0.0---172.31.255.255是私有地址。169.254.X.X是保留地址。
C類 192.0.0.1---223.255.255.254 192.168.X.X是私有地址
D類 224.0.0.1---239.255.255.254
E類 240.0.0.1---247.255.255.254
兩個DOS命令:
ipconfig 查看本機ip地址
ping 後面跟ip地址。測試本機與指定的ip地址間的通信是否有問題
特殊的IP地址:
127.0.0.1 迴環地址(表示本機)
x.x.x.255 廣播地址
x.x.x.0 網絡地址
端口號:
正在運行的程序的標識。
有效端口:0~65535,其中0~1024系統使用或保留端口。
協議:
通信的規則
UDP:
把數據打包
數據有限制
不建立連接
速度快
不可靠
TCP:
建立連接通道
數據無限制
速度慢
可靠
舉例:
UDP:發短信
TCP:打電話
1.2 UDP通信編程
* UDP通信:
* 將數據源和目的封裝成數據包中,不需要建立連接;
* 每個數據報的大小在限制在64k;
* 因無連接,是不可靠協議;
* 不需要建立連接,速度快.
* Socket套接字:
* 網絡上具有唯一標識的IP地址和端口號組合在一起才能構成唯一能識別的標識符套接字.
* Socket原理機制:
* 通信的兩端都有Socket;
* 網絡通信其實就是Socket間的通信;
* 數據在兩個Socket間通過IO傳輸.
* UDP通信的步驟:
* A:創建DatagramSocket與DatagramPacket類
* B:建立發送端,接收端;
* C:建立數據包;
* D:調用Socket的發送接收方法;
* E:關閉Socket;
* F:發送端與接收端是兩個獨立的運行程序.
* DatagramSocket類:此類表示用來發送和接收數據報包的套接字.
案例代碼
/*
* 使用線程,不斷髮送數據
*/
public class SendData {
public static void main(String[] args) throws IOException,
UnknownHostException {
// 創建發送端對象,綁定到本地的12310端口,不指定端口時,默認使用的本機上可用的端口號
final DatagramSocket ds = new DatagramSocket(12311);
// 創建發送數據包
byte[] bys = new byte[1024];
// 設定發送到對方的數據,長度,地址,IP地址,端口
final DatagramPacket dp = new DatagramPacket(bys, bys.length,
InetAddress.getLocalHost(), 12309);
new Thread() {
@Override
public void run() {
// 設置數據併發送
Scanner sc = new Scanner(System.in);
while(true) {
String line = sc.nextLine();
if(line.equals("somnus")) {
break;
}
dp.setData(line.getBytes());
try {
ds.send(dp);
} catch (IOException e) {
e.printStackTrace();
}finally {
// 釋放資源
// ds.close();
}
}
}
}.start();
}
}
/*
* 使用線程,不斷接收數據
*/
public class ReceiveData {
public static void main(String[] args) throws IOException {
// 創建接收端套接字,綁定到本地的12309端口上
final DatagramSocket ds = new DatagramSocket(12309);
// 創建接收數據的套接字
byte[] bys = new byte[1024];
final DatagramPacket dp = new DatagramPacket(bys, bys.length);
// 接收數據並輸出
new Thread() {
@Override
public void run() {
try {
while(true) {
ds.receive(dp);
System.out.println(dp.getAddress().getHostAddress()+":"+new String(dp.getData(), 0, dp.getLength()));
}
} catch (IOException e) {
e.printStackTrace();
}finally {
// 釋放資源
ds.close();
}
}
}.start();
}
}
1.3 TCP通信編程
* TCP通信:
* 建立連接,形成傳輸數據的通道;
* 在連接中進行大數據量傳輸;
* 通過三次握手完成連接,是可靠協議;
* 必須建立連接,效率會稍低.
* TCP通信步驟:
* A:創建Socket客戶端和ServerSocket服務端對象;
* B:建立客戶端和服務器端;
* C:建立連接後,通過Socket中的IO流進行數據的傳輸;
* D:關閉socket;
* E:同樣,客戶端與服務器端是兩個獨立的應用程序.
案例代碼
/*
* 將文件上傳到服務器,客戶端
*/
public class UpCilent {
public static void main(String[] args) throws IOException {
// 獲取文件路徑
File file = getFile();
// 將文件名上傳到服務器進行校驗是否存在
Socket client = new Socket("127.0.0.1", 12306);
// 創建輸出流對象
BufferedOutputStream bos = new BufferedOutputStream(client.getOutputStream());
// 向服務器發送文件名
String fileName = file.getName();
bos.write(fileName.getBytes());
// 將緩衝區的數據刷出
bos.flush();
// 創建輸入流對象
BufferedInputStream bis = new BufferedInputStream(client.getInputStream());
// 獲取服務器對文件名校驗的結果
byte[] bys = new byte[1024];
int len = bis.read(bys);
String result = new String(bys, 0, len);
if("存在".equals(result)) {
System.out.println("您要上傳的文件已經存在,不能重複上傳!");
client.close();
return;
}
// 文件不存在,則上傳
BufferedInputStream bis2 = new BufferedInputStream(new FileInputStream(file));
while((len = bis2.read(bys)) != -1) {
bos.write(bys, 0, len);
bos.flush();
}
// 釋放資源
bis2.close();
client.close();
}
public static File getFile() {
// 定義鍵盤錄入對象
Scanner sc = new Scanner(System.in);
System.out.println("請輸入一個文件的路徑名:");
while(true) {
File file = new File(sc.nextLine());
if(!file.exists()) {
System.out.println("您輸入的文件路徑不存在,請重新輸入:");
} else if(file.isDirectory()) {
System.out.println("您輸入的是文件夾路徑,請輸入文件路徑:");
} else {
return file;
}
}
}
}
/*
* 上傳文件到服務器,服務器端
*/
public class FileServer {
public static void main(String[] args) throws IOException {
// 創建服務器socket對象
ServerSocket server = new ServerSocket(12306);
// 創建存儲接收客戶端文件的文件夾
final File update = new File("update");
if(! update.exists()) {
update.mkdir();
}
// 持續接收客戶端連接
while(true) {
final Socket s = server.accept();
// 創建線程接收客戶端連接
new Thread() {
public void run() {
try {
BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
byte[] bys = new byte[1024];
int len = bis.read(bys);
String fileName = new String(bys, 0, len);
File file = new File(update, fileName);
if(file.exists()) {
bos.write("存在".getBytes());
bos.flush();
// 文件存在,結束程序
s.close();
return;
} else {
// 文件不存在則返回標識
bos.write("不存在".getBytes());
bos.flush();
}
// 如果文件不存在,則上傳
BufferedOutputStream bos2 = new BufferedOutputStream(new FileOutputStream(file));
while((len = bis.read(bys)) != -1) {
bos2.write(bys, 0, len);
bos2.flush();
}
// 釋放資源
bos2.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
}