Java笔记 - 黑马程序员_07(多线程,线程同步,线程池,网络编程入门,UDP通信原理,TCP通信原理,commons-io工具类)
1. 實現(xiàn)多線程
1.1 進程
進程:是正在運行的程序
- 是系統(tǒng)進行資源分配鄭調(diào)用的獨立單位
- 每一個進程都有它自己的內(nèi)存空間和系統(tǒng)資源
1.2 線程
線程:是進程中的單個順序控制流,是一條執(zhí)行路徑
- 單線程:一個進程如果只有一條執(zhí)行路徑,則稱為單線程程序
- 多線程:一個進程如果有多條執(zhí)行路徑,則稱為多線程程序
舉例:
- 記事本程序
- 掃雷程序
1.3 多線程的實現(xiàn)方式(方式1)
方式1:繼承Thread類
- 定義一個類MyThread繼承Thread類
- 在MyThread類中重寫run()方法
- 創(chuàng)建MyThread類的對象
- 啟動線程
兩個小問題:
- 為什么要重寫run() 方法?
因為run() 是用來封裝被線程執(zhí)行的代碼
- run() 方法和start() 方法的區(qū)別?
run() :封裝線程執(zhí)行的代碼,直接調(diào)用,相當于普通方法的調(diào)用
start():啟動線程;然后由JVM調(diào)用此線程的run()方法
1.4 設(shè)置和獲取線程名稱
Thread類中設(shè)置和獲取線程名稱的方法
- void setName(String name):將此線程的名稱更改為等于參數(shù)name
- String getName() :返回此線程的名稱
- 通過構(gòu)造方法也可以設(shè)置線程名稱
如何獲取main() 方法所在的線程名稱?
- public static Thread currentThread() 返回對當前正在執(zhí)行的線程對象的引用
1.5 線程調(diào)度
線程有兩種調(diào)度模型
- 分時調(diào)度模型:所有線程輪流使用CPU的使用權(quán),平均分配每個線程占用CPU的時間片
- 搶占式調(diào)度模型:優(yōu)先讓優(yōu)先級高的線程使用CPU,如果線程的優(yōu)先級相同,那么會隨機選擇一個,優(yōu)先級高的線程獲取的CPU時間片相對多一些
- Java使用的是搶占式調(diào)度模型
假如計算機只有一個CPU,那么CPU在某一個時刻只能執(zhí)行一條指令,線程只有得到CPU時間片,也就是使用權(quán),
才可以執(zhí)行指令。所以說多線程程序的執(zhí)行是有隨機性,因為誰搶到CPU的使用權(quán)是不一定的
Thread類中設(shè)置和獲取線程優(yōu)先級的方法
- public final int getPriority() :返回此線程的優(yōu)先級
- public final void setPriority(int newPriority):更改此線程的優(yōu)先級
1.6 線程控制
| static void sleep(long millis) | 使當前正在執(zhí)行的線程停留(暫停執(zhí)行)指定的毫秒數(shù) |
| void join() | 等待這個線程死亡 |
| void setDaemon(boolean on) | 將此線程標記為守護線程,當運行的線程都是守護線程時,Java虛擬機將退出 |
static void sleep(long millis) 使當前正在執(zhí)行的線程停留(暫停執(zhí)行)指定的毫秒數(shù)
//1. package demo_04;public class ThreadSleep extends Thread {public ThreadSleep() {}public ThreadSleep(String name) {super(name);}@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + ":" + i);try {//static void sleep(long millis)使當前正在執(zhí)行的線程以指定的毫秒數(shù)暫停(暫時停止執(zhí)行),具體取決于系統(tǒng)定時器和調(diào)度程序的精度和準確性Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}} }//2. package demo_04;//static void sleep(long millis)使當前正在執(zhí)行的線程以指定的毫秒數(shù)暫停(暫時停止執(zhí)行),具體取決于系統(tǒng)定時器和調(diào)度程序的精度和準確性public class ThreadSleepDemo {public static void main(String[] args) {ThreadSleep ts1 = new ThreadSleep("曹操");ThreadSleep ts2 = new ThreadSleep("劉備");ThreadSleep ts3 = new ThreadSleep("孫權(quán)");ts1.start();ts2.start();ts3.start();} }void join() 等待這個線程死亡
//1. package demo_04;public class ThreadJoin extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName()+":"+i);}} }//2. package demo_04; //void join() 等待這個線程死亡 public class ThreadJoinDemo {public static void main(String[] args) {//創(chuàng)建線程類對象ThreadJoin tj1 = new ThreadJoin();ThreadJoin tj2 = new ThreadJoin();ThreadJoin tj3 = new ThreadJoin();tj1.setName("張三");tj2.setName("李四");tj3.setName("王五");tj1.start();try {//void join() 等待這個線程死亡tj1.join();} catch (InterruptedException e) {e.printStackTrace();}tj2.start();tj3.start();} }void setDaemon(boolean on) 將此線程標記為守護線程,當運行的線程都是守護線程時,Java虛擬機將退出
//1. package demo_04;public class ThreadDaemon extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println();}} }//2. package demo_04; //void setDaemon(boolean on) 將此線程標記為守護線程,當運行的線程都是守護線程時,Java虛擬機將退出 public class ThreadDaemonDemo {public static void main(String[] args) {ThreadDaemon td1 = new ThreadDaemon();ThreadDaemon td2 = new ThreadDaemon();td1.setName("關(guān)羽");td1.setName("張飛");//設(shè)置主線程為劉備Thread.currentThread().setName("劉備");//設(shè)置守護線程td1.setDaemon(true);td2.setDaemon(true);for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName()+":"+i);}} }1.7 線程生命周期
1.8 多線程的實現(xiàn)方式(方式2)
方式2:實現(xiàn)Runnable接口
- 定義一個類MyRunnable實現(xiàn)Runnablef接口
- 在MyRunnable類中重寫run()方法
- 創(chuàng)建MyRunnable類的對象
- 創(chuàng)建Thread類的對象,把MyRunnable對像作為構(gòu)造方法的參數(shù)
- 啟動線程
多線程的實現(xiàn)方案有兩種
- 繼承Thread類
- 實現(xiàn)Runnable接口
相比繼承Thread類,實現(xiàn)Runnablef接口的好處
- 避免了Java單繼承的局限性
- 適合多個相同程序的代碼去處理同一個資源的情況,把線程和程序的代碼、數(shù)據(jù)有效分離,較好的體現(xiàn)了面向?qū)ο蟮脑O(shè)計思想
2. 線程同步
案例:賣票
需求:某電影院目前正在上映國產(chǎn)大片,共有100張票,而它有3個窗口賣票,請設(shè)計一個程序模擬該電影院賣票
思路:
①定義一個類SellTicket實現(xiàn)Runnablef接口,里面定義一個成員變量:private int tickets=100;
②在SellTicket類中重寫run() 方法實現(xiàn)賣票,代碼步驟如下:
A:判斷票數(shù)大于0,就賣票,并告知是哪個窗口賣的
B:賣了票之后,總票數(shù)要減1
C:票沒有了,也可能有人來問,所以這里用死循環(huán)讓賣票的動作一直執(zhí)行
③定義一個測試類SellTicketDemo,里面有main方法,代碼步驟如下
A:創(chuàng)建SellTicket類的對象
B:創(chuàng)建三個Thread類的對象,把SellTicket對象作為構(gòu)造方法的參數(shù),并給出對應(yīng)的窗口名稱
C:啟動線程
2.1 買票案例的思考
剛才講解了電影院賣票程序,好像沒有什么問題。但是在實際生活中,售票時出票也是需要時間的所以,在出售一張票的時候,需要一點時間的延遲,接下來我們?nèi)バ薷馁u票程序中賣票的動作:每次出票時間100毫秒,用sleep() 方法實現(xiàn)
賣票出現(xiàn)了問題:
問題原因:
- 線程執(zhí)行的隨機性導致的
2.2 賣票案例數(shù)據(jù)安全問題解決
為什么出現(xiàn)問題?(這也是我們判斷多線程程序是否會有數(shù)據(jù)安全問題的標準)
- 是否是多線程環(huán)境
- 是否有共享數(shù)據(jù)
- 是否有多條語句操作共享數(shù)據(jù)
如何解決多線程安全問題呢?
- 基本思想:讓程序沒有安全問題的環(huán)境
怎么實現(xiàn)呢?
- 把多條語句操作共享數(shù)據(jù)的代碼給鎖起來,讓任意時刻只能有一個線程執(zhí)行即可
- Java提供了同步代碼塊的方式來解決(如下2.3)
2.3 同步代碼塊
鎖多條語句操作共享數(shù)據(jù),可以使用同步代碼塊實現(xiàn)
格式:
synchronized(任意對象){多條語句操作共享數(shù)據(jù)的代碼 }- synchronized(任意對象):就相當于給代碼加鎖了,任意對象就可以看成是一把鎖
同步的好處和弊端:
- 好處:解決了多線程的數(shù)據(jù)安全問題
- 弊端:當線程很多時,因為每個線程都會去判斷同步上的鎖,這是很耗費資源的,無形中會降低程序的運行效率
2.4 同步方法
同步方法:就是把synchronized關(guān)鍵字加到方法上
格式:
修飾符 synchronized 返回值類型 方法名(方法參數(shù)){}同步方法的鎖對象是什么呢?
- this
同步靜態(tài)方法:就是把synchronized關(guān)鍵字加到靜態(tài)方法上
格式:
修飾符 static synchronized 返回值類型 方法名(方法參數(shù)){}同步靜態(tài)方法的鎖對象是什么呢?
- 類名.class
2.5 線程安全的類
StringBuffer
- 線程安全,可變的字符序列
- 從版本JDK5開始,被StringBuilder替代。通常應(yīng)該使用StringBuilder類,因為它支持所有相同的操作,但它更快,因為它不執(zhí)行同步
Vector
- 從Java2平臺v1.2開始,該類改進了List接口,使其成為Java Collections Framework的成員。與新的集合實現(xiàn)不同,Vector被同步。如果不需要線程安全的實現(xiàn),建議使用ArrayList代替Vector
Hashtable
- 該類實現(xiàn)了一個哈希表,它將鍵映射到值。任何非null對像都可以用作鍵或者值
- 從Java2平臺v1.2開始,該類進行了改進,實現(xiàn)了Map接口,使其成為Java Collections Framework的成員。
與新的集合實現(xiàn)不同,Hashtable被同步。如果不需要線程安全的實現(xiàn),建議使用HashMap代替Hashtable
2.6 Lock鎖
雖然我們可以理解同步代碼塊和同步方法的鎖對象問題,但是我們并沒有直接看到在哪里加上了鎖,在哪里釋放了鎖,為了更清晰的表達如何加鎖和釋放鎖,JDK5以后提供了一個新的鎖對象Lock
Lock實現(xiàn)提供比使用synchronized() 方法和語句可以獲得更廣泛的鎖定操作
Lock中提供了獲得鎖和釋放鎖的方法:
- void lock() :獲得鎖
- void unlock() :釋放鎖
Lock是接口不能直接實例化,這里采用它的實現(xiàn)類ReentrantLock來實例化
ReentrantLock的構(gòu)造方法:
- ReentrantLock() :創(chuàng)建一個ReentrantLock的實例
3 線程池
Java提供了線程池技術(shù),讓線程可以重復利用,解決線程頻繁創(chuàng)建和銷毀的問題,提高運行效率。
創(chuàng)建線程池
Executors類是線程池的工具類,通過Executors.工具類可以創(chuàng)建線程池。
| static ExecutorService newFixedThreadPool(int nThreads) | 創(chuàng)建一個線程池,參數(shù)為池中的線程數(shù)。 |
使用線程池
- ExecutorService代表線程池,該類中提供了submit方法用于處理提交的任務(wù)。
- 調(diào)用submit(任務(wù))方法時,線程池會分配池中空閑的線程去執(zhí)行對應(yīng)的任務(wù)。
| submit(Runnable task) | 提交Runnable類型的任務(wù) |
| submit(Callabletask) | 提交Callable類型的任務(wù) |
| void shutdown() | 關(guān)閉連接池 |
創(chuàng)建任務(wù)的兩種方式:
- 實現(xiàn)Runnable:接口,重寫run方法。
- 實現(xiàn)Callable<返回值類型>接口,重寫call方法。
3.1 線程池Runable方法(案例)
//1. package com.demo_2線程池Runnable接口;public class MyRunnable implements Runnable{@Overridepublic void run() {String name = Thread.currentThread().getName();System.out.println(name+"執(zhí)行了...");} }//2.測試類 package com.demo_2線程池Runnable接口;import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;public class Demo {public static void main(String[] args) {//創(chuàng)建線程數(shù)量為3的線程池ExecutorService pool = Executors.newFixedThreadPool(3);//使用線程池提交任務(wù)// submit(任務(wù))MyRunnable mr = new MyRunnable();pool.submit(mr);pool.submit(mr);pool.submit(mr);pool.submit(mr);//線程池中的線程都是出于活躍狀態(tài),代碼不會停止//把線程池關(guān)閉,線程會全部銷毀//pool.shutdown(); //不要關(guān)閉} }3.2 線程池Callable方法(案例)
//1. package com.demo_3Callable方法;import java.util.Random; import java.util.concurrent.Callable;public class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {String name = Thread.currentThread().getName();System.out.println(name+"執(zhí)行了....");Random r = new Random();int i = r.nextInt(10);System.out.println(i);return i;} }//2.測試類 package com.demo_3Callable方法;import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future;public class CallableDemo {public static void main(String[] args) throws Exception {//創(chuàng)建線程池ExecutorService pool = Executors.newFixedThreadPool(3);//提交MyCallable任務(wù)MyCallable mc = new MyCallable();//線程池執(zhí)行任務(wù),并把返回值裝到future中Future<Integer> f = pool.submit(mc);//通過future的get方法,獲取返回值Integer a = f.get();System.out.println("a="+a);//關(guān)閉線程池(不建議使用,線程池關(guān)閉線程里的東西全部銷毀)pool.shutdown();} }案例:使用線程池完成求和計算
需求:使用線程池方式創(chuàng)建兩個線程任務(wù):分段計算1~20000之間的數(shù)字和。
1.線程1計算1~10000之間的數(shù)字和,并返回結(jié)果。
2.線程2計算10001~20000之間的數(shù)字和,并返回結(jié)果。
3.提交任務(wù),獲取計算結(jié)果進行合并,打印最終結(jié)果。
分析:因為要返回求和結(jié)果,使用Callable來實現(xiàn)。
4. 網(wǎng)絡(luò)編程入門
4.1 網(wǎng)絡(luò)編程概述
計算機網(wǎng)絡(luò)
- 是指將地理位置不同的具有獨立功能的多臺計算機及其外部設(shè)備,通過通信線路連接起來,在網(wǎng)絡(luò)操作系統(tǒng),網(wǎng)絡(luò)管理軟件及網(wǎng)絡(luò)通信協(xié)議的管理和協(xié)調(diào)下,實現(xiàn)資源共享和信息傳遞的計算機系統(tǒng)
網(wǎng)絡(luò)編程
- 在網(wǎng)絡(luò)通信協(xié)議下,實現(xiàn)網(wǎng)絡(luò)互連的不同計算機上運行的程序間可以進行數(shù)據(jù)交換
4.2 網(wǎng)絡(luò)編程三要素
IP地址
- 要想讓網(wǎng)絡(luò)中的計算機能夠互相通信,必須為每臺計算機指定一個標識號,通過這個標識號來指定要接收數(shù)據(jù)的計算機和識別發(fā)送的計算機,而P地址就是這個標識號。也就是設(shè)備的標識
端口
- 網(wǎng)絡(luò)的通信,本質(zhì)上是兩個應(yīng)用程序的通信。每臺計算機都有很多的應(yīng)用程序,那么在網(wǎng)絡(luò)通信時,如何區(qū)分這些應(yīng)用程序呢?如果說P地址可以唯一標識網(wǎng)絡(luò)中的設(shè)備,那么端口號就可以唯一標識設(shè)備中的應(yīng)用程序了。也就是應(yīng)用程序的標識
協(xié)議
- 通過計算機網(wǎng)絡(luò)可以使多臺計算機實現(xiàn)連接,位于同一個網(wǎng)絡(luò)中的計算機在進行連接和通信時需要遵守一定的規(guī)則,這就好比在道路中行駛的汽車一定要遵守交通規(guī)唄則一樣。在計算機網(wǎng)絡(luò)中,這些連接和通信的規(guī)則被稱為網(wǎng)絡(luò)通信協(xié)議,它對數(shù)據(jù)的傳輸格式、傳輸速率、傳輸步驟等做了統(tǒng)一規(guī)定,通信雙方必須同時遵守才能完成數(shù)據(jù)交換。常見的協(xié)議有UDP協(xié)議和TCP協(xié)議
4.3 IP地址
IP地址:是網(wǎng)絡(luò)中設(shè)備的唯一標識
P地址分為兩大類
- IPv4:是給每個連接在網(wǎng)絡(luò)上的莊機分配一個32bi地址。按照TCP八P規(guī)定,P地址用二進制來表示,每個P地址長32bit,也就是4個字節(jié)。例破如一個采用二進制形式的P地址是“11000000101010000000000101000010°”,這么長的地址,處理起來也太費勁了。為了方便使用,P地址經(jīng)常被寫成十進制的形式,中間使用符號“”分隔不同的字節(jié)。于是,上面的1P地址可以表示為"192.168.1.66”。P地址的這種表示法叫做“點分十進制表示法”,這顯然比1和0容易記憶得多
- IPV6:由于互聯(lián)網(wǎng)的蓬勃發(fā)展,P地址的需求量愈來愈大,但是網(wǎng)絡(luò)地址資源有限,使得P的分配越發(fā)緊張。為了擴大地址空間,通過Pv6重新定義地址空間,采用128位地址長度,每16個字節(jié)一組,分成8組十六進制數(shù),這樣就解決了網(wǎng)絡(luò)地址資源數(shù)量不夠的問題
常用命令:
- ipconfig:查看本機IP地址
- ping IP地址:檢查網(wǎng)絡(luò)是否連通
特殊IP地址:
- 127.0.0.1:是回送地址,可以代表本機地址,般用來測試使用
4.4 InetAddress的使用
為了方便我們對lP地址的獲取和操作,Java提供了一個類InetAddress供我們使用
InetAddress:此類表示Internet協(xié)議 (IP) 地址
| static InetAddress getByName(String host) | 確定主機名稱的P地址。主機名稱可以是機器名稱,也可以是P地址 |
| String getHostName() | 獲取此P地址的主機名 |
| String getHostAddress() | 返回文本顯示中的IP地址字符串 |
4.5 端口
端口:設(shè)備上應(yīng)用程序的唯一標識
端口號:用兩個字節(jié)表示的整數(shù),它的取值范圍是065535。其中,01023之間的端口號用于一些知名的網(wǎng)絡(luò)服務(wù)和應(yīng)用,普通的應(yīng)用程序需要使用1024以上的端口號。如果端口號被另外一個服務(wù)或應(yīng)用所占用,會導致當前程序啟動失敗
4.6 協(xié)議
協(xié)議:計算機網(wǎng)絡(luò)中,連接和通信的規(guī)則被稱為網(wǎng)絡(luò)通信協(xié)議
UDP協(xié)議:
- 用戶數(shù)據(jù)報協(xié)議(User Datagram Protocol)
- UDP是無連接通信協(xié)議,即在數(shù)據(jù)傳輸時,數(shù)據(jù)的發(fā)送端和接收端不建立邏輯連接。簡單來說,當一臺計算機向另外一臺計算機發(fā)送數(shù)據(jù)時,發(fā)送端不會確認接收端是否存在,就會發(fā)出數(shù)據(jù),同樣接收端在收到數(shù)據(jù)時,也不會向發(fā)送端反饋是否收到數(shù)據(jù)。由于使用UDP協(xié)議消耗資源小,通信效率高,所以通常都會用于音頻、視頻和普通數(shù)據(jù)的傳輸
- 例如視頻會議通常采用UDP協(xié)議,因為這種情況即使偶爾丟失一兩個數(shù)據(jù)包,也不會對接收結(jié)果產(chǎn)生太大影響。但是在使用UDP協(xié)議傳送數(shù)據(jù)時,由于UDP的面向無連接性,不能保證數(shù)據(jù)的完整性,因此在傳輸重要數(shù)據(jù)時不建議使用UDP協(xié)議
TCP協(xié)議:
- 傳輸控制協(xié)議(Transmission Control Protocol)
- TCP協(xié)議是面向連接的通信協(xié)議,即傳輸數(shù)據(jù)之前,在發(fā)送端和接收總建立邏輯連接,然后再傳輸數(shù)據(jù),
它提供了兩臺計算機之間可靠無差錯的數(shù)據(jù)傳輸。在TCP連接中必須要明確客戶端與服務(wù)器端,由客戶端
向服務(wù)端發(fā)出連接請求,每次連接的創(chuàng)建都需要經(jīng)過“三次握手” - 三次握手:TCP協(xié)議中,在發(fā)送數(shù)據(jù)的準備階段,客戶端與服務(wù)器之間的三次交互,以保證連接的可靠
第一次握手,客戶端向服務(wù)器端發(fā)出連接請求,等待服務(wù)器確認
第二次握手,服務(wù)器端向客戶端回送一個響應(yīng),通知客戶端收到了連接請求
第三次握手,客戶端再次向服務(wù)器端發(fā)送確認信息,確認連接 - 完成三次握手,連接建立后,客戶端和服務(wù)器就可以開始進行數(shù)據(jù)傳輸了。由于這種面向連接的特性,TCP協(xié)議可以保證傳輸數(shù)據(jù)的安全,所以應(yīng)用十分廣泛。例如上傳文件、下載文件、瀏覽網(wǎng)頁等
5. UDP通信原理
5.1 UDP通信原理
UDP協(xié)議是一種不可靠的網(wǎng)絡(luò)協(xié)議,它在通信的兩端各建立一個Socket對象,但是這兩個Socket只是發(fā)送,接收數(shù)據(jù)的對象因此對于基于UDP協(xié)議的通信雙方而言,沒有所謂的客戶端和服務(wù)器的概念Java提供了DatagramSocket類作為基于UDP協(xié)議的Socket
5.2 UDP發(fā)送數(shù)據(jù)
發(fā)送數(shù)據(jù)的步驟
①創(chuàng)建發(fā)送端的Socket對象(DatagramSocket)
DatagramScoket()②創(chuàng)建數(shù)據(jù),并把數(shù)據(jù)打包
DatagramPacket(byte[]buf,int length,InetAddress address,int port)③調(diào)用DatagramSocket對象的方法發(fā)送數(shù)據(jù)
void send(DatagramPacket p)④關(guān)閉發(fā)送端
void close() package demo_02;/* 發(fā)送數(shù)據(jù)的步驟:創(chuàng)建發(fā)送端的Socket對象(DatagramSocket)創(chuàng)建數(shù)據(jù),并把數(shù)據(jù)打包調(diào)用DatagramSocket對象的方法發(fā)送數(shù)據(jù)關(guān)閉發(fā)送端 */import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress;public class SendDemo {public static void main(String[] args) throws IOException {//創(chuàng)建發(fā)送端的Socket對象(DatagramSocket)//DatagramSocket()//構(gòu)造數(shù)據(jù)報套接字并將其綁定到本地主機上的任何可用端口DatagramSocket ds = new DatagramSocket();//創(chuàng)建數(shù)據(jù),并把數(shù)據(jù)打包//DatagramPacket(byte[] buf, int length, InetAddress address, int port)//構(gòu)造用于發(fā)送長度的分組的數(shù)據(jù)報包 length指定主機上到指定的端口號byte[] bys = "hello,java".getBytes();DatagramPacket dp = new DatagramPacket(bys,bys.length, InetAddress.getByName("192.168.31.81"),10010);//調(diào)用DatagramSocket對象的方法發(fā)送數(shù)據(jù)//void send(DatagramPacket p)從此套接字發(fā)送數(shù)據(jù)報包 ds.send(dp);//關(guān)閉發(fā)送端ds.close();} }5.3 UDP接收數(shù)據(jù)
接收數(shù)據(jù)的步驟
①創(chuàng)建接收端的Socket對象(DatagramSocket)
DatagramSocket(int port)②創(chuàng)建一個數(shù)據(jù)包,用于接收數(shù)據(jù)
DatagramPacket(byte[]buf,int length)③調(diào)用DatagramSocket對象的方法接收數(shù)據(jù)
void receive(DatagramPacket p)④解析數(shù)據(jù)包,并把數(shù)據(jù)在控制臺顯示
byte[] getData() int getLength()⑤關(guān)閉接收端
void close() package demo_02; /* 接收數(shù)據(jù)的步驟:創(chuàng)建接收端的Socket對象(DatagramSocket)創(chuàng)建一個數(shù)據(jù)包,用于接收數(shù)據(jù)調(diào)用DatagramSocket對象的方法接收數(shù)據(jù)解析數(shù)據(jù)包,并把數(shù)據(jù)在控制臺顯示關(guān)閉接收端 */ import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket;public class ReceiveDemo {public static void main(String[] args) throws IOException {//創(chuàng)建接收端的Socket對象(DatagramSocket)DatagramSocket ds = new DatagramSocket(10010);//創(chuàng)建一個數(shù)據(jù)包,用于接收數(shù)據(jù)byte[] bys = new byte[1024];DatagramPacket dp = new DatagramPacket(bys,bys.length);//調(diào)用DatagramSocket對象的方法接收數(shù)據(jù)ds.receive(dp);//解析數(shù)據(jù)包,并把數(shù)據(jù)在控制臺顯示byte[] datas = dp.getData();int len = dp.getLength();System.out.println("數(shù)據(jù)是:"+new String(datas,0,len));//關(guān)閉接收端ds.close();} }5.4 UDP通信程序練習
按照下面的要求實現(xiàn)程序:
6. TCP通信原理
6.1 TCP通信原理
6.2 TCP發(fā)送數(shù)據(jù)
發(fā)送數(shù)據(jù)的步驟:
①創(chuàng)建客戶端的Socket對象(Socket)
Socket(String host,int port)②獲取輸出流,寫數(shù)據(jù)
OutputStream getOutputStream()③釋放資源
void close() package TCPDemo_04; /* 發(fā)送數(shù)據(jù)的步驟創(chuàng)建客戶端的Socket對象(Socket)獲取輸出流,寫數(shù)據(jù)科放資源 */ import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket;public class ClientDemo {public static void main(String[] args) throws IOException {//創(chuàng)建客戶端的Socket對象(Socket)//Socket(InetAddress address, int port)創(chuàng)建流套接字并將其連接到指定IP地址的指定端口號 // Socket s = new Socket(InetAddress.getByName("192.168.31.81"),10010);//Socket(String host, int port)創(chuàng)建流套接字并將其連接到指定主機上的指定端口號Socket s= new Socket("192.168.31.81",10010);//獲取輸出流,寫數(shù)據(jù)//OutputStream getOutputStream()返回此套接字的輸出流OutputStream os = s.getOutputStream();os.write("hello,java".getBytes());//釋放資源s.close();} }6.3 TCP接受數(shù)據(jù)
接收數(shù)據(jù)的步驟:
①創(chuàng)建服務(wù)器端的Socket對象(ServerSocket)
ServerSocket(int port)②監(jiān)聽客戶端連接,返回一個Socket對象
Socket accept()③獲取輸入流,讀數(shù)據(jù),并把數(shù)據(jù)顯示在控制臺
InputStream getlnputStream()④釋放資源
void close() package TCPDemo_04; /* 接收數(shù)據(jù)的步驟:創(chuàng)建服務(wù)器端的Socket對象(ServerSocket)監(jiān)聽客戶端連接,返回一個Sockety對象獲取輸入流,讀數(shù)據(jù),并把數(shù)據(jù)顯示在控制臺釋放資源 */ import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket;public class Serverdemo {public static void main(String[] args) throws IOException {//創(chuàng)建服務(wù)器端的Socket對象(ServerScoket)//ServerSocket(int port)創(chuàng)建綁定到指定端口的服務(wù)器套接字ServerSocket ss = new ServerSocket(10010);//監(jiān)聽客戶端連接,返回一個Sockety對象Socket s = ss.accept();//獲取輸入流,讀數(shù)據(jù),并把數(shù)據(jù)顯示在控制臺InputStream is = s.getInputStream();byte[] bys = new byte[1024];int len = is.read(bys);String data = new String(bys,0,len);System.out.println("數(shù)據(jù)是:"+data);//釋放資源ss.close();s.close();} }6.4 TCP通信程序練習
練習1
- 客戶端:發(fā)送數(shù)據(jù),接收服務(wù)器反饋
- 服務(wù)端:接收數(shù)據(jù),給出反饋
練習2
- 客戶端:數(shù)據(jù)來自于鍵盤錄入,直到輸入的數(shù)據(jù)是886,發(fā)送數(shù)據(jù)結(jié)束
- 服務(wù)器:接收到的數(shù)據(jù)在控制臺輸出
練習3
- 客戶端:數(shù)據(jù)來自于鍵盤錄入,直到輸入的數(shù)據(jù)是886,發(fā)送數(shù)據(jù)結(jié)束
- 服務(wù)器:接收到的數(shù)據(jù)寫入文本文件
練習4
- 客戶端:數(shù)據(jù)來自于文本文件
- 服務(wù)器:接收到的數(shù)據(jù)寫入文本文件
練習5
- 客戶端:數(shù)據(jù)來自于文本文件,接收服務(wù)器反饋
- 服務(wù)器:接收到的數(shù)據(jù)寫入文本文件,給出反饋
出現(xiàn)問題:程序一直等待
原因:讀數(shù)據(jù)的方法是阻塞式的
解決辦法:自定義結(jié)束標記使用shutdownOutput()方法(推薦)
練習6
- 客戶端:數(shù)據(jù)來自于文本文件,接收服務(wù)器反饋
- 服務(wù)器:接收到的數(shù)據(jù)寫入文本文件,給出反饋,代碼用線程進行封裝,為每一個客戶端開啟一個線程
commons-io工具類的使用
commons-io概述
- commons-io是apache開源基金組織提供的一組有關(guān)IO操作的類庫,可以挺提高lO功能開發(fā)的效率
- commons-io工具包提供了很多有關(guān)IO操作的類。有兩個主要的類FileUtils, IOUtils
FileUtils主要有如下方法:
| String readFileToString(File file, String encoding) | 讀取文件中的數(shù)據(jù),返回字符串 |
| void copyFile(File srcFile, File destFile) | 復制文件 |
| void copyDirectoryToDirectory(File srcDir, File destDir) | 復制文件夾 |
commons-io使用步驟:
更多內(nèi)容請訪問博主博客:逸樂的博客 - 今晚一起吃火鍋
文章如有紕漏請指出,整理不易多多包涵。
Java后續(xù)筆記將持續(xù)更新…
總結(jié)
以上是生活随笔為你收集整理的Java笔记 - 黑马程序员_07(多线程,线程同步,线程池,网络编程入门,UDP通信原理,TCP通信原理,commons-io工具类)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VBAProject调用mysql出错_
- 下一篇: Java零基础入门路径学习