第25天多线程、网络编程
多線程、網(wǎng)絡(luò)編程
JDK5的鎖和等待喚醒
Lock接口介紹
在JDK5之前,同步和鎖綁定在一起,同時鎖和等待喚醒也綁定在一起。在前學(xué)習(xí)同步代碼塊或同步方法的時候,線程要進(jìn)入同步首先需要隱式的獲取同步上的鎖對象。只有持有鎖對象的線程才能進(jìn)入到同步中。線程出同步的時候會隱式釋放鎖。鎖的獲取和釋放我們并無法操作。
?
到JDK5之后,將同步上的鎖的獲取和釋放修改為由編程人員自己控制。升級后將鎖單獨的封裝在Lock接口中。
?
?
JDK5中的Lock接口,它其實是在代替JDK5之前的同步方法或同步代碼塊。
?
將JDK5之前的隱式獲取鎖,修改為手動獲取:
同時將隱式釋放鎖,也修改為手動操作:
?
????如果使用JDK5的Lock接口,要求必須使用下面的模版代碼:
????
手動調(diào)用lock方法獲取鎖
try{
????????書寫的被同步的代碼
}finally{
????手動的調(diào)用unlock方法釋放鎖
}
Lock接口使用
/*
* 演示使用JDK5的Lock接口完成線程的同步
*/
class Ticket implements Runnable{
????
????private int num = 100;
????
????// 定義Lock接口的對象
????private Lock loc = new ReentrantLock();
????public void run(){
????????while(true){
????????????// 手動獲取鎖
????????????loc.lock(); // 從這里開始的代碼就會被同步
????????????try{
????????????????if( num > 0 ){
????????????????????System.out.println(Thread.currentThread().getName()+"....."+num);
????????????????????num--;
????????????????}
????????????}finally{
????????????????// 手動釋放鎖
????????????????loc.unlock(); // 同步結(jié)束
????????????}
????????}
????}
}
public class ThreadTest {
????public static void main(String[] args) {
????????
????????Ticket task= new Ticket();
????????
????????Thread t = new Thread( task );
????????Thread t2 = new Thread( task );
????????
????????t.start();
????????t2.start();
????}
}
Condition接口介紹
?
Condition 將 Object 監(jiān)視器方法(wait、notify 和 notifyAll)分解成截然不同的對象,以便通過將這些對象與任意 Lock 實現(xiàn)組合使用,為每個對象提供多個等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和語句的使用,Condition 替代了 Object 監(jiān)視器方法的使用。
?
wait方法被下面方法代替
?
notify 被下面方法代替
?
notifyAll:
Condition接口使用
/*
* 單生產(chǎn)單消費 使用JDK5中的Lock接口和Condition接口替換
*/
// 專門定義一個負(fù)責(zé)描述保存和取出線程的操作的資源類
class Resource {
????
????// 定義成員變量,充當(dāng)保存和取出的容器
????private Object[] objs = new Object[1];
????
????// 定義JDK5中的Lock接口對象
????private Lock loc = new ReentrantLock();
????
????// 定義監(jiān)視保存線程的等待和喚醒對象
????private Condition pro_con = loc.newCondition();
????// 定義監(jiān)視取消線程的等待和喚醒對象
????private Condition con_con = loc.newCondition();
????// 提供一個保存數(shù)據(jù)的方法
????public void save( Object obj ) {
????????loc.lock();
????????try{
????????????// 判斷能否操作容器
????????????if( objs[0] != null ){
????????????????// 判斷成立 說明保存的線程不能保存,需要等待
????????????????try { pro_con.await(); } catch( InterruptedException e ){ }
????????????}
????????????// 將數(shù)據(jù)保存到容器中
????????????objs[0] = obj;
????????????System.out.println(Thread.currentThread().getName()+" 正在保存的數(shù)據(jù)是:"+objs[0]);
????????????con_con.signal();
????????}finally{
????????????loc.unlock();
????????}
????????
????}
????
????// 提供一個取出數(shù)據(jù)的方法
????public void get(){
????????loc.lock();
????????try{
????????????if( objs[0] == null ){
????????????????// 判斷成立,說明沒有數(shù)據(jù),不能取出,需要等待
????????????????try { con_con.await(); } catch( InterruptedException e ){ }
????????????}
????????????// 打印取出的數(shù)據(jù)
????????????System.out.println(Thread.currentThread().getName() + " 正在取出的數(shù)據(jù)::::" +objs[0]);
????????????objs[0] = null;
????????????// 消費結(jié)束,需要通知生產(chǎn)者線程
????????????pro_con.signal();
????????}finally{
????????????loc.unlock();
????????}
????}
}
?
// 書寫保存數(shù)據(jù)線程的任務(wù)
class Productor implements Runnable {
?
????private Resource r ;
????// 書寫構(gòu)造方法的目的是在明確線程的任務(wù)的時候,
????// 可以通過構(gòu)造方法告訴線程的任務(wù)它們操作的資源對象
????public Productor( Resource r){
????????this.r = r ;
????}
????public void run() {
????????// 給資源中保存數(shù)據(jù)
????????while(true){
????????????r.save( "蘋果" );
????????}
????}
}
?
// 書寫取出數(shù)據(jù)的線程任務(wù)
class Consumer implements Runnable {
????
????private Resource r ;
????// 書寫構(gòu)造方法的目的是在明確線程的任務(wù)的時候,
????// 可以通過構(gòu)造方法告訴線程的任務(wù)它們操作的資源對象
????public Consumer( Resource r){
????????this.r = r ;
????}
????public void run() {
????????// 從資源中取出數(shù)據(jù)
????????while(true){
????????????r.get();
????????}
????}
}
?
// 測試類
public class ThreadTest {
????public static void main(String[] args) {
?
????????// 先要創(chuàng)建一個保存和取出操作的共同的資源對象
????????Resource r = new Resource();
????????
????????// 創(chuàng)建線程的任務(wù)對象
????????Productor pro = new Productor( r );
????????Consumer con = new Consumer( r );
????????
????????// 創(chuàng)建線程對象 ,這個線程負(fù)責(zé)保存數(shù)據(jù)
????????Thread t = new Thread( pro );
????????
????????// 創(chuàng)建線程對象 ,這個線程負(fù)責(zé)取出數(shù)據(jù)
????????Thread t2 = new Thread( con );
????????
????????// 開啟線程
????????t.start();
????????t2.start();
????}
}
多線程的細(xì)節(jié)
wait和sleep區(qū)別
wait:需要被喚醒,sleep時間到自然醒
wait:它只能放在同步中,sleep可以在同步中,也可以不在。
wait:可以指定時間,但大部分情況我們是不指定時間,而sleep必須指定時間
wait:它讓線程等待之后,線程會將鎖是否,而sleep如果在同步中,它讓線程休眠,這時線程是不會放鎖。
同步能不能添加在run方法上
按照語法規(guī)則,是可以在run方法上書寫同步的。但是實際開發(fā)中是不可能在run方法上添加同步的。
同步方法在線程執(zhí)行的時候,每個線程要進(jìn)入這個方法都需要獲取同步鎖,如果獲取不到鎖,線程就無法去執(zhí)行這個方法。而我們知道run方法是線程要執(zhí)行的任務(wù)方法,如果線程都進(jìn)不去run方法,相當(dāng)于線程根本就沒有拿到自己的任務(wù)。
線程組
線程組:將多個操作行為相同的線程,可以劃分到一個組中,然后我們不要去面對每個線程,而只要通過這個組操作組里面的所有線程。
?
如何將線程添加到線程組中:
在創(chuàng)建Thread對象的時候,可以根據(jù)Thread的構(gòu)造方法將線程添加到對應(yīng)的線程組中。
線程優(yōu)先級
Thread類中的API:每個線程都有一個優(yōu)先級,高優(yōu)先級線程的執(zhí)行優(yōu)先于低優(yōu)先級線程。
?
我們在創(chuàng)建線程的時候,可以指定每個線程的優(yōu)先級,如果沒有指定的話,這個線程優(yōu)先級默認(rèn)和執(zhí)行創(chuàng)建線程時所在的線程優(yōu)先級相同。主線程的優(yōu)先級默認(rèn)為5.
?
線程的優(yōu)先級: 1 ~ 10 ,一般建議如果需要設(shè)計線程的優(yōu)先級設(shè)置為 1 或 5 或 10。
修改線程的優(yōu)先級:
獲取線程的優(yōu)先級:
????
????
????
????注意:高優(yōu)先級的線程被CPU執(zhí)行的概率會被低優(yōu)先級的高,但是并不意味著低優(yōu)先級的線程CPU不執(zhí)行。
守護(hù)線程
守護(hù)線程:每個線程都可以或不可以標(biāo)記為一個守護(hù)程序。當(dāng)且僅當(dāng)創(chuàng)建線程是守護(hù)線程時,新線程才是守護(hù)程序。
前臺線程:從主程序開始執(zhí)行的那個線程一定是前臺線程。主線程屬于前臺線程(非守護(hù)線程)。
守護(hù)線程也被稱為后臺線程,或者被稱為用戶線程,這些線程它們依然可以去運行線程的任務(wù),但是如果程序中的前臺線程全部結(jié)束,這時不管后臺(守護(hù))線程的任務(wù)是否結(jié)束,守護(hù)線程會自動停止運行。
?
?
/*
* 演示守護(hù)線程
*/
class Demo implements Runnable{
????
????public void run(){
????????for( int i = 0 ; ; i++){
????????????System.out.println(Thread.currentThread().getName()+"...."+i);
????????}
????}
}
?
public class TheradDemo {
????public static void main(String[] args) {
????????// 執(zhí)行main方法的線程,一定是前臺線程
????????
????????Demo d = new Demo();
????????
????????// 下面創(chuàng)建的線程和主線程都屬于前臺線程
????????Thread t = new Thread(d);
????????Thread t2 = new Thread(d);
????????
????????// 人為的將創(chuàng)建出來的線程修改為后臺(守護(hù)線程),一定要在開啟線程之前修改
????????t.setDaemon(true);
????????t2.setDaemon(true);
????????
????????t.start();
????????t2.start();
????????
????????for( int i = 0 ; i < 20 ; i++){
????????????System.out.println(Thread.currentThread().getName()+"-----"+i);
????????}
????}
}
定時器介紹
定時器:讓設(shè)備可以定時的去(重復(fù))執(zhí)行某個功能。
????
定時器類:
????
????
????構(gòu)造方法:
????
????
????下面的方法是給Timer(定時器)對象綁定任務(wù)
????
?
????/*
* 演示定時器
*/
public class TimerDemo {
????public static void main(String[] args) {
????????
????????// 創(chuàng)建定時器對象
????????Timer t = new Timer();
????????
????????/*
???????? * 給定時器指定任務(wù)
???????? * schedule(TimerTask task, long delay, long period)
???????? * TimerTask task : 定時器要執(zhí)行的任務(wù)
???????? * long delay : 當(dāng)前時間往后延時多久,開始執(zhí)行任務(wù)
???????? * long period : 到執(zhí)行任務(wù)的時間點之后,每隔多久時間重復(fù)執(zhí)行一次任務(wù)
???????? */
????????final Random r = new Random();
????????t.schedule( new TimerTask(){
????????????@Override
????????????public void run() {
????????????????// 在run方法中書寫具體Java代碼完成定時器需要做事情
????????????????System.out.println("你好");
????????????????File file = new File("e:/abc/"+r.nextInt()+".txt");
????????????????try {
????????????????????file.createNewFile();
????????????????} catch (IOException e) {
????????????????????e.printStackTrace();
????????????????}
????????????}
????????}, 1000, 1000);????????
????}
}
網(wǎng)絡(luò)介紹
網(wǎng)絡(luò)介紹(了解)
網(wǎng)絡(luò):通過一些中間的設(shè)備,可以將終端設(shè)備連接在一起,并且這些終端設(shè)備之間可以進(jìn)行數(shù)據(jù)的交互。
?
中間設(shè)備:網(wǎng)線、交換機、路由器、無線設(shè)備、衛(wèi)星等。
?
終端設(shè)備:電腦、服務(wù)器、手機、智能家電等。
?
網(wǎng)絡(luò)分成:局域網(wǎng)、城域網(wǎng)、廣域網(wǎng)。
?
網(wǎng)絡(luò)模型介紹(了解)
由于網(wǎng)絡(luò)中的設(shè)備太多,于是將工作在網(wǎng)絡(luò)中的不同設(shè)備功能(職責(zé))進(jìn)行劃分,將網(wǎng)絡(luò)化成七層(網(wǎng)絡(luò)模型):
OSI(Open System Interconnection開放系統(tǒng)互連)參考模型 。
1.層物理層:主要定義物理設(shè)備標(biāo)準(zhǔn),如網(wǎng)線的接口類型、光纖的接口類型、各種傳輸介質(zhì)的傳輸速率等。它的主要作用是傳輸比特流(就是由1、0轉(zhuǎn)化為電流強弱來進(jìn)行傳輸,到達(dá)目的地后在轉(zhuǎn)化為1、0,也就是我們常說的數(shù)模轉(zhuǎn)換與模數(shù)轉(zhuǎn)換)。這一層的數(shù)據(jù)叫做比特。 2.層數(shù)據(jù)鏈路層:主要將從物理層接收的數(shù)據(jù)進(jìn)行MAC地址(網(wǎng)卡的地址)的封裝與解封裝。常把這一層的數(shù)據(jù)叫做幀。在這一層工作的設(shè)備是交換機,數(shù)據(jù)通過交換機來傳輸。 3.層網(wǎng)絡(luò)層:主要將從下層接收到的數(shù)據(jù)進(jìn)行IP地址(例192.168.0.1)的封裝與解封裝。在這一層工作的設(shè)備是路由器,常把這一層的數(shù)據(jù)叫做數(shù)據(jù)包。 4.層傳輸層:定義了一些傳輸數(shù)據(jù)的協(xié)議和端口號(WWW端口80等),如:TCP(傳輸控制協(xié)議,傳輸效率低,可靠性強,用于傳輸可靠性要求高,數(shù)據(jù)量大的數(shù)據(jù)),UDP(用戶數(shù)據(jù)報協(xié)議,與TCP特性恰恰相反,用于傳輸可靠性要求不高,數(shù)據(jù)量小的數(shù)據(jù),如QQ聊天數(shù)據(jù)就是通過這種方式傳輸?shù)?#xff09;。 主要是將從下層接收的數(shù)據(jù)進(jìn)行分段和傳輸,到達(dá)目的地址后再進(jìn)行重組。常常把這一層數(shù)據(jù)叫做段。 5.會話層:通過傳輸層(端口號:傳輸端口與接收端口)建立數(shù)據(jù)傳輸?shù)耐贰V饕谀愕南到y(tǒng)之間發(fā)起會話或者接受會話請求(設(shè)備之間需要互相認(rèn)識可以是IP也可以是MAC或者是主機名) 6.表示層:主要是進(jìn)行對接收的數(shù)據(jù)進(jìn)行解釋、加密與解密、壓縮與解壓縮等(也就是把計算機能夠識別的東西轉(zhuǎn)換成人能夠能識別的東西(如圖片、聲音等)。 7.應(yīng)用層: 主要是一些終端的應(yīng)用,比如說FTP(各種文件下載),WEB(IE瀏覽),QQ之類的(可以把它理解成我們在電腦屏幕上可以看到的東西.就是終端應(yīng)用)。
網(wǎng)絡(luò)三要素(重點掌握)
IP介紹(重點)
IP:它本質(zhì)是連接在網(wǎng)絡(luò)中那個終端設(shè)備的一個數(shù)字標(biāo)識。如果我們需要進(jìn)行網(wǎng)絡(luò)通信,這時我們就必須知道通信對方的IP地址是多少,才能和對方進(jìn)行通信。
?
IP地址:
????它被分成5類:A、B、C、D、E。
?
平時我們上網(wǎng)的時候,從來不手動設(shè)置IP地址,這時IP地址由寬帶提供商提供。
?
如何查詢自己電腦的IP地址:
?
IP地址:它是連接在網(wǎng)絡(luò)中終端設(shè)備的唯一的數(shù)字標(biāo)識。
MAC地址:每個網(wǎng)卡都有一個網(wǎng)卡地址,這個地址也被稱為物理地址。每個網(wǎng)卡在生產(chǎn)的時候就已經(jīng)固定死(全球唯一)。
網(wǎng)卡是設(shè)備的物理標(biāo)識,它不容易記憶,也不容器操作。但是我們的確可以通過網(wǎng)卡地址找到需要通信的設(shè)備。但是實際應(yīng)用中,程序不會根據(jù)網(wǎng)卡地址通信。
IP地址,邏輯地址:它可以分配給任何一個連接在網(wǎng)絡(luò)中的設(shè)備。
?
網(wǎng)卡地址和IP地址:
????網(wǎng)卡地址:可以理解成手機的唯一編號(*#06#)。
????IP地址:可以理解成手機號碼。
?
?
了解的內(nèi)容:其實每個網(wǎng)卡在出廠的時候已經(jīng)分配了一個IP地址。
這個地址:本地回環(huán)地址。127.0.0.1
域名解析(了解)
IP地址是我們唯一訪問網(wǎng)絡(luò)中設(shè)備的路徑。平時我們上網(wǎng)的時候根本沒有使用IP地址訪問任何網(wǎng)絡(luò)中的信息。
平時在瀏覽器的地址欄中輸入域名(www.baidu.com),通過域名訪問網(wǎng)絡(luò)中的資源數(shù)據(jù)。
?
當(dāng)我們在瀏覽器的地址欄中輸入域名之后,其實背后對應(yīng)的將域名解析成對應(yīng)的IP地址,最后還是在使用IP地址訪問。
?
關(guān)于域名解析成IP地址:域名解析
????1、先通過操作系統(tǒng)本地的hosts文件中查詢當(dāng)前的域名有沒有對應(yīng)的IP地址,如果有就會使用hosts文件中的IP,作為當(dāng)前域名的對應(yīng)的IP地址訪問。
????????C:\Windows\System32\drivers\etc\hosts
????????
????2、如果第一步解析IP地址失敗,這時系統(tǒng)會自動到DNS服務(wù)器上解析。DNS服務(wù)器上會有全球所有的網(wǎng)站對應(yīng)的IP地址。查詢到域名對應(yīng)的ip地址,就會使用這個ip地址訪問。如果DNS服務(wù)器解析失敗,這時說明域名有問題。
端口介紹(重點)
通過IP地址,可以訪問到連接在網(wǎng)絡(luò)中的某個終端設(shè)備。設(shè)備中肯定會運行很多的應(yīng)用程序(軟件),最終我們需要和設(shè)備中的某個應(yīng)用軟件進(jìn)行數(shù)據(jù)交互。
?
運行在終端設(shè)備中的任何應(yīng)用軟件,它們在這個設(shè)備中都有一個唯一的標(biāo)識,這個標(biāo)識我們稱為軟件在此設(shè)備中的端口號。
?
端口號:從0~65535之間,一般0~1024之間的端口號,是給系統(tǒng)軟件使用的時候,因此我們自己編程中,開發(fā)的程序需要綁定端口的時候,建議使用1025~65535之間的端口號。
?
總結(jié):
????IP:它本質(zhì)是網(wǎng)絡(luò)中的電腦的標(biāo)識。
????端口:電腦中運行的軟件的標(biāo)識。
協(xié)議介紹(重點)
協(xié)議:雙方需要共同遵守的規(guī)則。在網(wǎng)絡(luò)編程中,協(xié)議是在規(guī)范通信雙方需要遵守的數(shù)據(jù)交互格式。
我們學(xué)習(xí)的網(wǎng)絡(luò)編程中的協(xié)議,主要是OSI模型中傳輸層協(xié)議(底層協(xié)議):
????
UDP協(xié)議:用戶數(shù)據(jù)報文包協(xié)議。
????????通信雙方不同關(guān)心對方是否在接收數(shù)據(jù)。發(fā)送方只管發(fā)送數(shù)據(jù),接收方如果在,就可以接收到數(shù)據(jù),如果不在,數(shù)據(jù)就會被丟棄。
????????UDP協(xié)議,傳輸快,效率高,但不安全。不能發(fā)送大數(shù)據(jù)。
????????UDP協(xié)議,一般用在實時聊天等程序底層。
?
????TCP協(xié)議:傳輸控制協(xié)議。
????????通信的雙方,必須經(jīng)常三次握手,建立數(shù)據(jù)交互的通道。然后雙方在這個通道中進(jìn)行數(shù)據(jù)傳遞。如果有一方斷開通道,這時通道就被破壞,無法在繼續(xù)通信。
????TCP協(xié)議:它主要用在對數(shù)據(jù)安全性要求較高的軟件底層。傳遞慢,效率低,但安全。
?
總結(jié):最終我們通過網(wǎng)絡(luò)通信,需要上門介紹的三個要素:
協(xié)議:雙方通信的規(guī)則
ip:對方的設(shè)備標(biāo)識
端口:對方設(shè)備中運行的軟件標(biāo)識
網(wǎng)絡(luò)編程
IP對象(理解+編碼)
連接在網(wǎng)絡(luò)中的任何設(shè)備都有一個IP地址。因此Java也將IP地址封裝成一個對象,如果我們在編程中需要操作IP地址,可以直接使用InetAddress對象完成。
Java中的網(wǎng)絡(luò)編程相關(guān)的類和接口都在java.net包下:
?
Ipv4:它采用的4個數(shù)字作為ip地址。每個數(shù)字范圍0~255之間。它也是IP的第四個版本。
Ipv6:它是IP地址的第六個版本。它采用的是八個數(shù)字作為ip地址。首選形式為 x:x:x:x:x:x:x:x,其中這些 'x' 是八個 16 位地址段的十六進(jìn)制值。
?
InetAddress類它沒有對外提供構(gòu)造方法,只能通過其中的靜態(tài)方法獲取對象:
?
/*
* 演示InetAddress對象
*/
public class IPDemo {
????public static void main(String[] args) throws UnknownHostException {
????????
????????method2();
????}
?
????public static void method2() throws UnknownHostException {
????????
????????InetAddress[] ints = InetAddress.getAllByName("www.sina.com.cn");
????????
????????for (InetAddress inet : ints) {
????????????System.out.println(inet.getHostAddress());
????????}
????}
????public static void method1() throws UnknownHostException {
????????/*
???????? * 使用靜態(tài)方法獲取IP對象
???????? * getByName(String host)
???????? * String host: 表示是需要封裝的IP地址,
???????? * 字符串可以書寫:IP地址、 主機名、域名
???????? */
????????InetAddress inet = InetAddress.getByName("www.baidu.com");
????????
????????// 獲取IP地址 getHostAddress()
????????String ip = inet.getHostAddress();
????????/*
???????? * 獲取主機名
???????? * getHostName() 有時無法解析出對方的主機名稱時,這個值就會變成IP地址
???????? */
????????String name = inet.getHostName();
????????System.out.println(ip+"...."+name);
????}
}
Socket對象(理解)
Socket : 網(wǎng)絡(luò)套接字。
?
UDP協(xié)議編程
DatagramSocket對象(理解)
DatagramSocketL:它是用來發(fā)送和接收數(shù)據(jù)報包的通信端點(終端設(shè)備)對象。
?
?
DatagramPacket對象(理解)
DatagramPacket:它相當(dāng)于打包或拆包的對象。
UDP發(fā)送端(重點理解+編碼)
?
/*
* 簡單演示基于UDP協(xié)議發(fā)送方實現(xiàn)
*/
public class UdpSendDemo {
????public static void main(String[] args) throws Exception {
????????
????????// 創(chuàng)建發(fā)送方對象
????????DatagramSocket ds = new DatagramSocket(9191);
????????
????????/*
???????? * 創(chuàng)建打包對象
???????? * DatagramPacket(byte[] buf, int length, InetAddress address, int port)
???????? * byte[] buf : 被發(fā)送的數(shù)據(jù)
???????? * int length : 發(fā)送的數(shù)據(jù)的長度
???????? * InetAddress address : 接收方的IP地址對象
???????? * int port : 接收方的端口
???????? */
????????byte[] buf = "有人犯困啦!UDP肯定掛掉!!!".getBytes();
????????int length = buf.length;
????????InetAddress address = InetAddress.getByName("192.168.49.40");
????????int port = 9292;
????????DatagramPacket dp = new DatagramPacket( buf , length , address , port);
????????
????????// 發(fā)送數(shù)據(jù)
????????ds.send(dp);
????????
????????// 關(guān)閉發(fā)送方
????????ds.close();
????}
}
UDP接收端(重點理解+編碼)
/*
* 簡單實現(xiàn)基于UDP協(xié)議的接收方
*/
public class UdpReceDemo {
????public static void main(String[] args) throws Exception {
????????
????????// 創(chuàng)建接收方對象
????????DatagramSocket ds = new DatagramSocket(9292);
????????
????????/*
???????? * 創(chuàng)建拆包對象
???????? * DatagramPacket(byte[] buf, int length)
???????? * byte[] buf : 臨時用于存儲接收到的數(shù)據(jù)的容器
???????? * int length : 臨時用于存儲數(shù)據(jù)的場地大小
???????? */
????????DatagramPacket dp = new DatagramPacket( new byte[1024] , 1024 );
????????
????????// 接收數(shù)據(jù)
????????ds.receive(dp);
????????
????????// 獲取接收到的數(shù)據(jù)
????????byte[] buf = dp.getData();
????????// 接收到的數(shù)據(jù)長度
????????int length = dp.getLength();
????????// 獲取發(fā)送方的ip
????????String ip = dp.getAddress().getHostAddress();
????????// 獲取發(fā)送方的端口號
????????int port = dp.getPort();
????????System.out.println(ip+".."+port + ", 數(shù)據(jù)是:"+ new String( buf , 0 , length ));
????????
????????// 關(guān)閉接收方
????????ds.close();
????}
}
UDP練習(xí)
需求:
發(fā)送方鍵盤錄入字符串?dāng)?shù)據(jù),將字符串?dāng)?shù)據(jù)發(fā)送給接收方,接收方接收到之后,統(tǒng)計出其中字母字符的個數(shù),然后將結(jié)果發(fā)送給發(fā)送方。
?
發(fā)送端(編碼實戰(zhàn))
?
/*
* 發(fā)送方:
* ????1、鍵盤錄入字符串?dāng)?shù)據(jù),
* ????2、將數(shù)據(jù)發(fā)送給接收方
* ????3、接收 接收方發(fā)來的結(jié)果數(shù)據(jù)
*/
public class UdpSendTest {
????public static void main(String[] args) throws IOException {
?
????????// 創(chuàng)建發(fā)送方對象
????????DatagramSocket ds = new DatagramSocket(9393);
????????
????????// 創(chuàng)建Scanner對象
????????Scanner sc = new Scanner( System.in );
????????System.out.println("請輸入數(shù)據(jù):");
????????String line = sc.nextLine();
????????
????????// 創(chuàng)建打包對象
????????DatagramPacket send_dp = new DatagramPacket(
???????????????? line.getBytes(),
???????????????? line.getBytes().length,
???????????????? InetAddress.getByName("192.168.49.40"),
???????????????? 9494
????????????????);
????????// 發(fā)送數(shù)據(jù)
????????ds.send(send_dp);
????????///數(shù)據(jù)已經(jīng)發(fā)送給接收方,需要接收數(shù)據(jù)//
????????// 創(chuàng)建拆包對象
????????DatagramPacket rece_dp = new DatagramPacket( new byte[1024] , 1024 );
????????// 接收數(shù)據(jù)
????????ds.receive(rece_dp);
????????// 獲取數(shù)據(jù)
????????String s = new String( rece_dp.getData() , 0 , rece_dp.getLength() );
????????System.out.println(s);
????????
????????// 關(guān)閉
????????ds.close();
????}
}
接收端(編碼實戰(zhàn))
/*
* 接收方:
* ????1、接收數(shù)據(jù)
* ????2、統(tǒng)計出其中的字母字符個數(shù)
* ????3、將結(jié)果發(fā)送給發(fā)送方
*/
public class UdpReceTest {
????public static void main(String[] args) throws Exception {
????????
????????// 創(chuàng)建接收方對象
????????DatagramSocket ds = new DatagramSocket( 9494 );
????????
????????// 創(chuàng)建拆包對象
????????DatagramPacket rece_dp = new DatagramPacket( new byte[1024] , 1024 );
????????// 接收數(shù)據(jù)
????????ds.receive(rece_dp);
????????// 獲取數(shù)據(jù)
????????String data = new String( rece_dp.getData() , 0 , rece_dp.getLength() ) ;
????????System.out.println(rece_dp.getAddress().getHostAddress()+"接收方接收到的數(shù)據(jù)是:"+data);
????????// 處理:統(tǒng)計字母字符個數(shù)
????????int count = 0;
????????// 遍歷字符串
????????for( int i = 0 ; i < data.length() ; i++ ){
????????????// 取出字符串中的每個字符
????????????char ch = data.charAt(i);
????????????// 判斷是否是字母字符
????????????if( (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ){
????????????????count++;
????????????}
????????}
????????// 統(tǒng)計結(jié)束之后,需要將結(jié)果發(fā)送給發(fā)送方
????????String s = "統(tǒng)計的結(jié)果是:"+count;
????????// 創(chuàng)建打包對象
????????DatagramPacket send_dp = new DatagramPacket(
????????????????s.getBytes(),
????????????????s.getBytes().length,
????????????????// 這里的IP地址是發(fā)送方的IP地址,可以通過上面的拆包對象獲取
????????????????rece_dp.getAddress(),
????????????????// 接收方的端口號
????????????????rece_dp.getPort()
????????????????);
????????/// 發(fā)送數(shù)據(jù)
????????ds.send(send_dp);
????????
????????// 關(guān)閉
????????ds.close();
????}
}
TCP編程
回顧IO流
????
TCP編程模型介紹(理解)
?
?
TCP客戶端(理解)
?
?
?
TCP服務(wù)端(理解)
?
TCP客戶端實現(xiàn)(重點+編碼)
?
?
?
TCP服務(wù)端實現(xiàn)(重點+編碼)
?
?
?
TCP練習(xí)
需求:
需求:客戶端鍵盤錄入數(shù)據(jù),發(fā)送給服務(wù)器,服務(wù)端將數(shù)據(jù)保存到磁盤中,服務(wù)端告訴客戶端"微博發(fā)送成功"。
?
?
?
?
?
客戶端實現(xiàn)
?
?
?
服務(wù)端實現(xiàn)
?
?
?
服務(wù)端開啟多線程
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/beyondcj/p/6270832.html
總結(jié)
以上是生活随笔為你收集整理的第25天多线程、网络编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于js对象引用的小例子
- 下一篇: LeetCode Number Comp