多線程+注解+發(fā)射+內(nèi)部類+socket基礎(chǔ)
大家好,?我是鹿是不是鹿, 以下是關(guān)于多線程+注解+發(fā)射+內(nèi)部類+socket通信相關(guān)的一些基礎(chǔ)知識(shí), 希望能給大家?guī)韼椭?/p>
1.1??進(jìn)程
1.1.1?????概念
就是正在運(yùn)行的程序。也就是代表了程序鎖占用的內(nèi)存區(qū)域。
1.1.2?????特點(diǎn)
l??獨(dú)立性:進(jìn)程是系統(tǒng)中獨(dú)立存在的實(shí)體,它可以擁有自己的獨(dú)立的資源,每一個(gè)進(jìn)程都擁有自己私有的地址空間。在沒有經(jīng)過進(jìn)程本身允許的情況下,一個(gè)用戶進(jìn)程不可以直接訪問其他進(jìn)程的地址空間。
l??動(dòng)態(tài)性:進(jìn)程與程序的區(qū)別在于,程序只是一個(gè)靜態(tài)的指令集合,而進(jìn)程是一個(gè)正在系統(tǒng)中活動(dòng)的指令集合。在進(jìn)程中加入了時(shí)間的概念,進(jìn)程具有自己的生命周期和各種不同的狀態(tài),這些概念在程序中都是不具備的。
l??并發(fā)性:多個(gè)進(jìn)程可以在單個(gè)處理器上并發(fā)執(zhí)行,多個(gè)進(jìn)程之間不會(huì)互相影響。
1.2??線程
1.2.1?????概念
線程(thread)是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位。它被包含在進(jìn)程之中,是進(jìn)程中的實(shí)際運(yùn)作單位。一個(gè)進(jìn)程可以開啟多個(gè)線程。
多線程擴(kuò)展了多進(jìn)程的概念,使得同一個(gè)進(jìn)程可以同時(shí)并發(fā)處理多個(gè)任務(wù)。
簡而言之,一個(gè)程序運(yùn)行后至少一個(gè)進(jìn)程,一個(gè)進(jìn)程里包含多個(gè)線程。
如果一個(gè)進(jìn)程只有一個(gè)線程,這種程序被稱為單線程。
如果一個(gè)進(jìn)程中有多條執(zhí)行路徑被稱為多線程程序。

1.2.2?????進(jìn)程和線程的關(guān)系

從上圖中可以看出一個(gè)操作系統(tǒng)中可以有多個(gè)進(jìn)程,一個(gè)進(jìn)程中可以有多個(gè)線程,每個(gè)進(jìn)程有自己獨(dú)立的內(nèi)存,每個(gè)線程共享一個(gè)進(jìn)程中的內(nèi)存,每個(gè)線程又有自己獨(dú)立的內(nèi)存。(記清這個(gè)關(guān)系,非常重要?。?/p>
????所以想使用線程技術(shù),得先有進(jìn)程,進(jìn)程的創(chuàng)建是OS創(chuàng)建的,你能實(shí)現(xiàn)嗎?不能,一般都是c或者c++語言完成的。
1.3??多線程的特性
1.3.1?????隨機(jī)性

1.3.2?????線程狀態(tài)

線程生命周期,總共有五種狀態(tài):
1)???新建狀態(tài)(New):當(dāng)線程對(duì)象對(duì)創(chuàng)建后,即進(jìn)入了新建狀態(tài),如:Thread t = new MyThread();
2)???就緒狀態(tài)(Runnable):當(dāng)調(diào)用線程對(duì)象的start()方法(t.start();),線程即進(jìn)入就緒狀態(tài)。處于就緒狀態(tài)的線程,只是說明此線程已經(jīng)做好了準(zhǔn)備,隨時(shí)等待CPU調(diào)度執(zhí)行,并不是說執(zhí)行了t.start()此線程立即就會(huì)執(zhí)行;
3)???運(yùn)行狀態(tài)(Running):當(dāng)CPU開始調(diào)度處于就緒狀態(tài)的線程時(shí),此時(shí)線程才得以真正執(zhí)行,即進(jìn)入到運(yùn)行狀態(tài)。注:就緒狀態(tài)是進(jìn)入到運(yùn)行狀態(tài)的唯一入口,也就是說,線程要想進(jìn)入運(yùn)行狀態(tài)執(zhí)行,首先必須處于就緒狀態(tài)中;
4)???阻塞狀態(tài)(Blocked):處于運(yùn)行狀態(tài)中的線程由于某種原因,暫時(shí)放棄對(duì)CPU的使用權(quán),停止執(zhí)行,此時(shí)進(jìn)入阻塞狀態(tài),直到其進(jìn)入到就緒狀態(tài),才有機(jī)會(huì)再次被CPU調(diào)用以進(jìn)入到運(yùn)行狀態(tài);
?
5)???根據(jù)阻塞產(chǎn)生的原因不同,阻塞狀態(tài)又可以分為三種:
?
a)???等待阻塞:運(yùn)行狀態(tài)中的線程執(zhí)行wait()方法,使本線程進(jìn)入到等待阻塞狀態(tài);
b)???同步阻塞:線程在獲取synchronized同步鎖失敗(因?yàn)殒i被其它線程所占用),它會(huì)進(jìn)入同步阻塞狀態(tài);
c)???其他阻塞:通過調(diào)用線程的sleep()或join()或發(fā)出了I/O請(qǐng)求時(shí),線程會(huì)進(jìn)入到阻塞狀態(tài)。當(dāng)sleep()狀態(tài)超時(shí)、join()等待線程終止或者超時(shí)、或者I/O處理完畢時(shí),線程重新轉(zhuǎn)入就緒狀態(tài)。
6)???死亡狀態(tài)(Dead):線程執(zhí)行完了或者因異常退出了run()方法,該線程結(jié)束生命周期。
?
1.4??多線程創(chuàng)建1:繼承Thread
1.4.1?????概述
Thread類本質(zhì)上是實(shí)現(xiàn)了Runnable接口的一個(gè)實(shí)例,代表一個(gè)線程的實(shí)例。啟動(dòng)線程的唯一方法就是通過Thread類的start()實(shí)例方法。Start()方法是一個(gè)native方法,它將通知底層操作系統(tǒng),最終由操作系統(tǒng)啟動(dòng)一個(gè)新線程,操作系統(tǒng)將執(zhí)行run()方法。這種方式實(shí)現(xiàn)多線程很簡單,通過自己的類直接extend Thread,并復(fù)寫run()方法,就可以啟動(dòng)新線程并執(zhí)行自己定義的run()方法。
模擬開啟多個(gè)線程,每個(gè)線程調(diào)用run()方法
1.4.2?????常用方法
String getName()
??????????返回該線程的名稱。
static Thread currentThread()
??????????返回對(duì)當(dāng)前正在執(zhí)行的線程對(duì)象的引用。
void setName(String name)
??????????改變線程名稱,使之與參數(shù)?name?相同。
static void sleep(long millis)
?????在指定的毫秒數(shù)內(nèi)讓當(dāng)前正在執(zhí)行的線程休眠(暫停執(zhí)行),此操作受到系統(tǒng)計(jì)時(shí)器和調(diào)度程序精度和準(zhǔn)確性的影響。
void start()
??????????使該線程開始執(zhí)行;Java?虛擬機(jī)調(diào)用該線程的?run?方法。
?
Thread(String name)
??????????分配新的?Thread?對(duì)象。
?
1.4.3?????測試
1.5??多線程創(chuàng)建2:實(shí)現(xiàn)Runnable接口
1.5.1?????概述
如果自己的類已經(jīng)extends另一個(gè)類,就無法多繼承,此時(shí),可以實(shí)現(xiàn)一個(gè)Runnable接口。
1.5.2?????常用方法
void run()
??????????使用實(shí)現(xiàn)接口?Runnable?的對(duì)象創(chuàng)建一個(gè)線程時(shí),啟動(dòng)該線程將導(dǎo)致在獨(dú)立執(zhí)行的線程中調(diào)用對(duì)象的?run?方法。
1.5.3?????測試
1.5.4?????比較

1.6??售票案例
設(shè)計(jì)4個(gè)售票窗口,總計(jì)售票100張。
用多線程的程序設(shè)計(jì)并寫出代碼。
1.6.1?????方案1:繼承Thread
1.6.2?????方案2:實(shí)現(xiàn)Runnable
1.6.3?????問題
1、??????每次創(chuàng)建線程對(duì)象,都會(huì)生成一個(gè)tickets變量值是100,創(chuàng)建4次對(duì)象就生成了400張票了。不符合需求,怎么解決呢?能不能把tickets變量在每個(gè)對(duì)象間共享,就保證多少個(gè)對(duì)象都是賣這100張票。--??用靜態(tài)修飾
2、??????產(chǎn)生超賣,-1張、-2張。
3、??????產(chǎn)生重賣,同一張票賣給多人。
4、??????多線程安全問題是如何出現(xiàn)的?常見情況是由于線程的隨機(jī)性+訪問延遲。
5、??????以后如何判斷程序有沒有線程安全問題?在多線程程序中+有共享數(shù)據(jù)+多條語句操作共享數(shù)據(jù)。
2.1??同步鎖
把有可能出現(xiàn)問題的代碼包起來,一次只讓一個(gè)線程執(zhí)行。通過sychronized關(guān)鍵字實(shí)現(xiàn)同步。
當(dāng)多個(gè)對(duì)象操作共享數(shù)據(jù)時(shí),可以使用同步鎖解決線程安全問題。
2.1.1?????synchronized
synchronized(對(duì)象){
????需要同步的代碼;
}
2.1.1?????特點(diǎn)
1、?前提1,同步需要兩個(gè)或者兩個(gè)以上的線程。
2、?前提2,多個(gè)線程間必須使用同一個(gè)鎖。
3、?同步的缺點(diǎn)是會(huì)降低程序的執(zhí)行效率,??為了保證線程安全,必須犧牲性能。
4、?可以修飾方法稱為同步方法,使用的鎖對(duì)象是this。
5、?可以修飾代碼塊稱為同步代碼塊,鎖對(duì)象可以任意。
2.1.2?????改造
2.2??單例設(shè)計(jì)模式
2.2.1?????概念
單例模式可以說是大多數(shù)開發(fā)人員在實(shí)際中使用最多的,常見的Spring默認(rèn)創(chuàng)建的bean就是單例模式的。
單例模式有很多好處,比如可節(jié)約系統(tǒng)內(nèi)存空間,控制資源的使用。
其中單例模式最重要的是確保對(duì)象只有一個(gè)。
簡單來說,保證一個(gè)類在內(nèi)存中的對(duì)象就一個(gè)。
RunTime就是典型的單例設(shè)計(jì),我們通過對(duì)RunTime類的分析,一窺究竟。
2.2.2?????源碼剖析
2.2.3?????餓漢式
2.2.4?????懶漢式
2.3??注解
2.3.1?????概念
注解很厲害,它可以增強(qiáng)我們的java代碼,同時(shí)利用反射技術(shù)可以擴(kuò)充實(shí)現(xiàn)很多功能。它們被廣泛應(yīng)用于三大框架底層。傳統(tǒng)我們通過xml文本文件聲明方式,而現(xiàn)在最主流的開發(fā)都是基于注解方式,代碼量少,框架可以根據(jù)注解去自動(dòng)生成很多代碼,從而減少代碼量,程序更易讀。例如最火爆的SpringBoot就完全基于注解技術(shù)實(shí)現(xiàn)。
注解設(shè)計(jì)非常精巧,初學(xué)時(shí)覺得很另類甚至多余,甚至垃圾。有了java代碼干嘛還要有@注解呢?但熟練之后你會(huì)贊嘆,它竟然可以超越j(luò)ava代碼的功能,讓java代碼瞬間變得強(qiáng)大。大家慢慢體會(huì)吧。
常見的元注解:@Target、@Retention,jdk提供將來描述我們自定義的注解的注解。聽起來好繞,別著急,做兩個(gè)例子,立刻清晰?,F(xiàn)在現(xiàn)有“元注解”這個(gè)概念。
2.3.2?????分類
l??JDK自帶注解
l??元注解
l??自定義注解
2.3.3?????JDK注解
JDK注解的注解,就5個(gè):
l??@Override
l??@Deprecated標(biāo)記就表明這個(gè)方法已經(jīng)過時(shí)了,但我就要用,別提示我過期
l??@SuppressWarnings(“deprecation”)?忽略警告
l??@SafeVarargs jdk1.7出現(xiàn),堆污染,不常用
l??@FunctionallInterface jdk1.8出現(xiàn),配合函數(shù)式編程拉姆達(dá)表達(dá)式,不常用
2.3.4?????元注解
描述注解的注解,就5個(gè):
l??@Target?注解用在哪里:類上、方法上、屬性上
l??@Retention?注解的生命周期:源文件中、class文件中、運(yùn)行中
l??@Inherited?允許子注解繼承
l??@Documented?生成javadoc時(shí)會(huì)包含注解,不常用
l??@Repeatable注解為可重復(fù)類型注解,可以在同一個(gè)地方多次使用,不常用
2.4??元注解
2.4.1?????@Target???ElementType.class
描述注解的使用范圍:
l??ElementType.ANNOTATION_TYPE????????應(yīng)用于注釋類型
l??ElementType.CONSTRUCTOR?????????應(yīng)用于構(gòu)造函數(shù)
l??ElementType.FIELD???????????????????應(yīng)用于字段或?qū)傩?/p>
l??ElementType.LOCAL_VARIABLE??????應(yīng)用于局部變量
l??ElementType.METHOD??????????????應(yīng)用于方法級(jí)
l??ElementType.PACKAGE?????????????應(yīng)用于包聲明
l??ElementType.PARAMETER???????????應(yīng)用于方法的參數(shù)
l??ElementType.TYPE????????????????應(yīng)用于類的元素
2.4.2?????@Retention??RetentionPolicy.class
定義了該注解被保留的時(shí)間長短,某些注解僅出現(xiàn)在源代碼中,而被編譯器丟棄;
而另一些卻被編譯在class文件中;?編譯在class文件中的注解可能會(huì)被虛擬機(jī)忽略,而另一些在class被裝載時(shí)將被讀取。
為何要分有沒有呢?沒有時(shí),反射就拿不到,從而就無法去識(shí)別處理。
l??SOURCE????????在源文件中有效(即源文件保留)
l??CLASS?????????在class文件中有效(即class保留)
l??RUNTIME???????????在運(yùn)行時(shí)有效(即運(yùn)行時(shí)保留)
2.5??自定義注解
2.5.1?????定義注解
//1,定義注解
//1.1,設(shè)置注解的使用范圍@Target,啥都不寫,哪兒都能用
//@Target({ElementType.METHOD})//作用于方法上
//@Target({ElementType.FIELD})//作用于屬性上
@Target({ElementType.METHOD , ElementType.PACKAGE})//作用范圍
@Retention(RetentionPolicy.SOURCE)//生命周期
@Target({ElementType.TYPE})//作用于類上
@interface?Test{
????//3,定義屬性
????int age() default 0;//使用時(shí),必須給age屬性賦值,如:age=X。除非設(shè)置好默認(rèn)值。
//()不是參數(shù),也不能寫參數(shù),只是特殊語法
???
????//4,特殊屬性value
????String value() default "";//使用時(shí),必須給value屬性賦值,如:X??|??value=X。除非設(shè)置好默認(rèn)值
}
注意:注解的語法寫法和常規(guī)java的語法寫法不同
2.5.2?????使用注解
//2,使用注解
//@Test
//5,注解的組合屬性
@Test(value="",age=0)
class HelloTest{
//??@Test(value="",age=0)
????String name;
}
2.5.3?????解析注解
判斷注解是否存在
3.1??反射
3.1.1?????概念
Reflection(反射)?是?Java?程序開發(fā)語言的特征之一,它允許運(yùn)行中的?Java?程序?qū)ψ陨磉M(jìn)行檢查,或者說“自審”,也有稱作“自省”。反射非常強(qiáng)大,它甚至能直接操作程序的私有屬性。我們前面學(xué)習(xí)都有一個(gè)概念,private的只能類內(nèi)部訪問,外部是不行的,但這個(gè)規(guī)定被反射赤裸裸的打破了。
反射就像一面鏡子,它可以在運(yùn)行時(shí)獲取一個(gè)類的所有信息,可以獲取到任何定義的信息(包括成員變量,成員方法,構(gòu)造器等),并且可以操縱類的字段、方法、構(gòu)造器等部分。
3.1.2?????為什么需要反射
好好的我們new User();?不是很好,為什么要去通過反射創(chuàng)建對(duì)象呢?
那我要問你個(gè)問題了,你為什么要去餐館吃飯呢?
例如:我們要吃個(gè)牛排大餐,如果我們自己創(chuàng)建,就什么都得管理。
好處是,每一步做什么我都很清晰,壞處是什么都得自己實(shí)現(xiàn),那不是累死了。牛接生你管,吃什么你管,屠宰你管,運(yùn)輸你管,冷藏你管,烹飪你管,上桌你管。就拿做菜來說,你能有特級(jí)廚師做的好?
那怎么辦呢?有句話說的好,專業(yè)的事情交給專業(yè)的人做,飼養(yǎng)交給農(nóng)場主,屠宰交給劊子手,烹飪交給特級(jí)廚師。那我們干嘛呢?
我們翹起二郎腿直接拿過來吃就好了。
再者,飯店把東西做好,不能扔到地上,我們?nèi)熘园?,那不是都成原始人了。那怎么辦呢?很簡單,把做好的東西放在一個(gè)容器中吧,如把牛排放在盤子里。
在開發(fā)的世界里,spring就是專業(yè)的組織,它來幫我們創(chuàng)建對(duì)象,管理對(duì)象。我們不在new對(duì)象,而直接從spring提供的容器中beans獲取即可。Beans底層其實(shí)就是一個(gè)Map<String,Object>,最終通過getBean(“user”)來獲取。而這其中最核心的實(shí)現(xiàn)就是利用反射技術(shù)。
總結(jié)一句,類不是你創(chuàng)建的,是你同事或者直接是第三方公司,此時(shí)你要或得這個(gè)類的底層功能調(diào)用,就需要反射技術(shù)實(shí)現(xiàn)。有點(diǎn)抽象,別著急,我們做個(gè)案例,你就立馬清晰。
3.1.3?????反射Class類對(duì)象
Class.forName(“類的全路徑”);
類名.class
對(duì)象.getClass();
3.1.4?????常用方法
獲得包名、類名
clazz.getPackage().getName()//包名
clazz.getSimpleName()//類名
clazz.getName()//完整類名
??!成員變量定義信息
getFields()//獲得所有公開的成員變量,包括繼承的變量
getDeclaredFields()//獲得本類定義的成員變量,包括私有,不包括繼承的變量
getField(變量名)
getDeclaredField(變量名)
!!構(gòu)造方法定義信息
getConstructor(參數(shù)類型列表)//獲得公開的構(gòu)造方法
getConstructors()//獲得所有公開的構(gòu)造方法
getDeclaredConstructors()//獲得所有構(gòu)造方法,包括私有
getDeclaredConstructor(int.class, String.class)
方法定義信息
getMethods()//獲得所有可見的方法,包括繼承的方法
getMethod(方法名,參數(shù)類型列表)
getDeclaredMethods()//獲得本類定義的方法,包括私有,不包括繼承的方法
getDeclaredMethod(方法名, int.class, String.class)
反射新建實(shí)例
c.newInstance();//執(zhí)行無參構(gòu)造
c.newInstance(6, "abc");//執(zhí)行有參構(gòu)造
c.getConstructor(int.class, String.class); //執(zhí)行含參構(gòu)造,獲取構(gòu)造方法
反射調(diào)用成員變量
c.getDeclaredField(變量名); //獲取變量
c.setAccessible(true); //使私有成員允許訪問
f.set(實(shí)例,?值); //為指定實(shí)例的變量賦值,靜態(tài)變量,第一參數(shù)給?null
f.get(實(shí)例); //訪問指定實(shí)例的變量的值,靜態(tài)變量,第一參數(shù)給?null
反射調(diào)用成員方法
獲取方法
Method m = c.getDeclaredMethod(方法名,?參數(shù)類型列表);
m.setAccessible(true) ;//使私有方法允許被調(diào)用
m.invoke(實(shí)例,?參數(shù)數(shù)據(jù)) ;//讓指定的實(shí)例來執(zhí)行該方法
3.2??反射的應(yīng)用
3.2.1?????獲取類對(duì)象
????private static void method() throws Exception {
???????Class clazz = Student.class;
???????Class<?> clazz2 = Class.forName("seday15.Student");
???????Class clazz3 = new Student().getClass();
??????
???????System.out.println(clazz.getName());
???????System.out.println(clazz2.getName());
???????System.out.println(clazz3.getName());
????}
3.2.2?????獲取構(gòu)造方法
private static void method3(Class clazz) {
???????Constructor[] cs = clazz.getDeclaredConstructors();
???????for (Constructor c : cs) {
???????????String name = clazz.getSimpleName();
???????????System.out.println(name);
??????????
???????????Class[] cs2 = c.getParameterTypes();//參數(shù)
???????????System.out.println(Arrays.toString(cs2));
??????????
???????}
??????
????}
?
3.2.3?????獲取成員方法
private static void method4(Class clazz) {
?????Method[] ms = clazz.getMethods();
???????for (Method m : ms) {
???????????String name = m.getName();
???????????System.out.println(name);
??????????
???????????Class<?>[] cs = m.getParameterTypes();
???????????System.out.println(Arrays.toString(cs));
???????}
????}
3.2.4?????獲取成員變量
????private static void method2(Class clazz) {
???????Field[] fs = clazz.getFields();//獲取public的屬性
???????for (Field f : fs) {
???????????String name = f.getName();
???????????String tname = f.getType().getSimpleName();
???????????System.out.println(name);
???????????System.out.println(tname);
???????}
????}
3.2.5?????創(chuàng)建對(duì)象
3.3??暴力反射
指可以將程序中的私有的屬性或者方法通過反射技術(shù),暴力的獲取到資源。需要使用的常見方法如下:

3.3.1?????創(chuàng)建Person類
class Person{
???
????private String name="jack";
????private int age = 30;
???
????private void show(int[] a) {
???????System.out.println("show()..."+Arrays.toString(a));
????}
????private void test() {
???????System.out.println("test()...");
????}
}
3.3.2?????測試
1、?獲取私有屬性值并修改
2、?獲取私有方法并執(zhí)行
3.4??內(nèi)部類
3.4.1?????概述
如果一個(gè)類存在的意義就是為指定的另一個(gè)類,可以把這個(gè)類放入另一個(gè)類的內(nèi)部。就是把類定義在類的內(nèi)部的情況就可以形成內(nèi)部類的形式。
A類中又定義了B類,B類就是內(nèi)部類。B類可以當(dāng)做A類的一個(gè)成員看待。
3.4.2????????特點(diǎn)
1、?內(nèi)部類可以直接訪問外部類中的成員,包括私有成員
2、?外部類要訪問內(nèi)部類的成員,必須要建立內(nèi)部類的對(duì)象
3、?在成員位置的內(nèi)部類是成員內(nèi)部類
4、?在局部位置的內(nèi)部類是局部內(nèi)部類
3.4.3????????成員內(nèi)部類
被private修飾
被static修飾
3.4.4????????匿名內(nèi)部類
匿名內(nèi)部類屬于局部內(nèi)部類,并且是沒有名字的內(nèi)部類。
4.1??網(wǎng)絡(luò)
查看本機(jī)ip地址


4.2??Socket
4.2.1????????概述
也叫套接字編程,是一個(gè)抽象層。
應(yīng)用程序可以通過它發(fā)送或接收數(shù)據(jù),可對(duì)其像對(duì)文件一樣的打開、讀寫和關(guān)閉等操作。套接字允許應(yīng)用程序?qū)/O插入到網(wǎng)絡(luò)中,并與網(wǎng)絡(luò)中的其他應(yīng)用程序進(jìn)行通信。網(wǎng)絡(luò)套接字是IP地址與端口與協(xié)議的組合。
Socket就是為網(wǎng)絡(luò)編程提供的一種機(jī)制?/?通信的兩端都有Socket
網(wǎng)絡(luò)通信其實(shí)就是Socket間的通信?/?數(shù)據(jù)在兩個(gè)Socket間通過IO傳輸

4.3??服務(wù)器端-ServerSocket
在服務(wù)器端,選擇一個(gè)端口號(hào),在指定端口上等待客戶端發(fā)起連接。
啟動(dòng)服務(wù):ServerSocket ss = new ServerSocket(端口);
等待客戶端發(fā)起連接,并建立連接通道:Sokcet socket = ss.accept();
4.4??客戶端-Socket
新建Socket對(duì)象,連接指定ip的服務(wù)器的指定端口
Socket s = new Socket(ip, port);
?
從Socket獲取雙向的流
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
4.5??入門案例
服務(wù)器端接收客戶端發(fā)來的hello,并給客戶端響應(yīng)hello。
4.5.1????????服務(wù)器端
說明其中,server端的accept()是阻塞的,客戶端不連接,服務(wù)器不執(zhí)行后面流程。
in.read()也是阻塞的,讀不到就死等。
4.5.2????????客戶端