網(wǎng)絡(luò)基礎(chǔ)(Socket通訊)

目錄

網(wǎng)絡(luò)分層

網(wǎng)絡(luò)分層——來(lái)源于極客時(shí)間之趣談網(wǎng)絡(luò)協(xié)議

1,應(yīng)用層:如常用的http協(xié)議屬于應(yīng)用層鱼填,定義了數(shù)據(jù)的包裝與解析規(guī)則药有。
2,傳輸層:包含TCP與UDP協(xié)議剔氏,這一層通常使用java封裝的Socket類(lèi)進(jìn)行數(shù)據(jù)的發(fā)送與接收塑猖。
3竹祷,網(wǎng)絡(luò)層:包含常用的IP協(xié)議以及路由協(xié)議谈跛。這一層用于指定數(shù)據(jù)的IP傳輸規(guī)則,包含傳輸路線(xiàn)塑陵,路由選擇等感憾。
4,鏈路層:包含常見(jiàn)的ARP協(xié)議令花,負(fù)責(zé)將IP地址解析為Mac地址(硬件地址)阻桅,從而找到對(duì)應(yīng)的設(shè)備
5,物理層:這一層是在物理設(shè)備上進(jìn)行數(shù)據(jù)的傳輸兼都,包含有線(xiàn)與無(wú)線(xiàn)通信嫂沉。

在地址欄輸入url后的流程?
1,使用DNS(域名系統(tǒng))解析域名,從而獲取url中的IP地址
2扮碧,使用IP地址與本地默認(rèn)的端口(80)建立TCP連接(3次握手)
3趟章,建立TCP連接后發(fā)起http請(qǐng)求
4杏糙,服務(wù)器收到請(qǐng)求并響應(yīng)HTTP請(qǐng)求,將對(duì)應(yīng)的html文本發(fā)送給瀏覽器
5蚓土,瀏覽器解析htm代碼,并請(qǐng)求htm代碼中的資源(如js宏侍、css圖片等)
6,斷開(kāi)TCP連接(4次揮手)
7蜀漆,瀏覽器對(duì)頁(yè)面進(jìn)行渲染呈現(xiàn)給用戶(hù)

HTTP

1谅河,HTTP(超文本傳輸協(xié)議):是一個(gè)基于請(qǐng)求與響應(yīng)模式的、無(wú)狀態(tài)的确丢、應(yīng)用層的協(xié)議绷耍,常基于TCP的連接方式鲜侥,默認(rèn)端口號(hào)為80锨天。特點(diǎn)如下:

1,簡(jiǎn)單快速:客戶(hù)向服務(wù)器請(qǐng)求數(shù)據(jù)時(shí)剃毒,只需傳送請(qǐng)求方法和路徑病袄。由于傳輸內(nèi)容少,故通信速度相對(duì)較快赘阀。
2益缠,靈活:HTTP允許傳輸任意類(lèi)型的數(shù)據(jù)對(duì)象。傳輸?shù)念?lèi)型由Content-Type加以標(biāo)記
3基公,無(wú)連接:每次連接只處理一個(gè)請(qǐng)求幅慌。服務(wù)器處理完客戶(hù)的請(qǐng)求,并收到客戶(hù)的應(yīng)答后轰豆,即斷開(kāi)連接胰伍。采用這種方式可以節(jié)省傳輸時(shí)間。由于使用TCP連接酸休,這種方式比較耗時(shí)并且效率不高骂租。
4,無(wú)狀態(tài):協(xié)議對(duì)于事務(wù)處理沒(méi)有記憶能力斑司。缺少狀態(tài)意味著如果后續(xù)處理需要前面的信息渗饮,則它必須重傳,這樣可能導(dǎo)致每次連接傳送的數(shù)據(jù)量增大宿刮』フ荆可以使用Cookie來(lái)解決無(wú)狀態(tài)的問(wèn)題,Cookie就相當(dāng)于一個(gè)通行證僵缺,第一次訪(fǎng)問(wèn)的時(shí)候給客戶(hù)端發(fā)送一個(gè)Cookie胡桃,當(dāng)客戶(hù)端再次來(lái)的時(shí)候,拿著Cookie(通行證)磕潮,那么服務(wù)器就知道這個(gè)是”老用戶(hù)“翠胰。

2懊纳,http協(xié)議的組成

  • 請(qǐng)求報(bào)文:請(qǐng)求行/請(qǐng)求頭/請(qǐng)求體

請(qǐng)求行:包含請(qǐng)求方法get/post、URI亡容、HTTP版本信息(如:http1.0)
請(qǐng)求頭:即header嗤疯,里面包含很多字段。比如使用Accept-Language可以設(shè)置返回?cái)?shù)據(jù)的語(yǔ)言類(lèi)型闺兢。
請(qǐng)求體:發(fā)送的數(shù)據(jù)茂缚。比如get、post請(qǐng)求的參數(shù)屋谭。

  • 響應(yīng)報(bào)文:狀態(tài)行/響應(yīng)頭/響應(yīng)體

狀態(tài)行:包含HTTP版本,狀態(tài)碼,狀態(tài)碼原因短語(yǔ)脚囊。通常使用狀態(tài)碼判斷結(jié)果。
響應(yīng)頭:返回的header
響應(yīng)體:請(qǐng)求服務(wù)器返回的數(shù)據(jù)桐磁。通常是我們需要使用的數(shù)據(jù)

  • 常用的http頭部字段
  • 通用首部字段(請(qǐng)求報(bào)文與響應(yīng)報(bào)文都會(huì)使用的首部字段)
    Date:創(chuàng)建報(bào)文時(shí)間
    Connection:連接的管理
    Cache-Control:緩存的控制
    Transfer-Encoding:報(bào)文主體的傳輸編碼方式
  • 請(qǐng)求首部字段(請(qǐng)求報(bào)文會(huì)使用的首部字段)
    Host:請(qǐng)求資源所在服務(wù)器
    Accept:可處理的媒體類(lèi)型
    Accept-Charset:可接收的字符集
    Accept-Encoding:可接受的內(nèi)容編碼
    Accept-Language:可接受的自然語(yǔ)言
  • 響應(yīng)首部字段(響應(yīng)報(bào)文會(huì)使用的首部字段)
    Accept-Ranges:可接受的字節(jié)范圍
    Location:令客戶(hù)端重新定向到的URI
    Server:HTTP服務(wù)器的安裝信息
  • 實(shí)體首部字段(請(qǐng)求報(bào)文與響應(yīng)報(bào)文的的實(shí)體部分使用的首部字段)
    Allow:資源可支持的HTTP方法
    Content-Type:實(shí)體主類(lèi)的類(lèi)型
    Content-Encoding:實(shí)體主體適用的編碼方式
    Content-Language:實(shí)體主體的自然語(yǔ)言
    Content-Length:實(shí)體主體的的字節(jié)數(shù)
    Content-Range:實(shí)體主體的位置范圍悔耘,一般用于發(fā)出部分請(qǐng)求時(shí)使用

3,請(qǐng)求方式:

GET:用于請(qǐng)求訪(fǎng)問(wèn)已經(jīng)被URI(統(tǒng)一資源標(biāo)識(shí)符)識(shí)別的資源,可以通過(guò)URL傳參給服務(wù)器
POST:用于傳輸信息給服務(wù)器,主要功能與GET方法類(lèi)似,但一般推薦使用POST方式
PUT:傳輸文件,報(bào)文主體中包含文件內(nèi)容,保存到對(duì)應(yīng)URI位置
HEAD:獲得報(bào)文首部,與GET方法類(lèi)似,只是不返回報(bào)文主體,一般用于驗(yàn)證URI是否有效
DELETE:刪除文件,與PUT方法相反,刪除對(duì)應(yīng)URI位置的文件
OPTIONS:查詢(xún)響應(yīng)URI支持的HTTP方法

  • get重點(diǎn)在從服務(wù)器上獲取資源我擂,post重點(diǎn)在向服務(wù)器發(fā)送數(shù)據(jù)衬以;
  • get傳輸數(shù)據(jù)是通過(guò)URL請(qǐng)求,以field(字段)= value的形式校摩,置于URL后看峻,并用"?"連接,多個(gè)請(qǐng)求數(shù)據(jù)間用"&"連接衙吩,如:http://127.0.0.1/Test/login.action?name=admin&password=admin互妓,這個(gè)過(guò)程用戶(hù)是可見(jiàn)的;post傳輸數(shù)據(jù)通過(guò)Http的post機(jī)制坤塞,將字段與對(duì)應(yīng)值封存在請(qǐng)求實(shí)體中發(fā)送給服務(wù)器冯勉,這個(gè)過(guò)程對(duì)用戶(hù)是不可見(jiàn)的;
  • get傳輸?shù)臄?shù)據(jù)量小摹芙,因?yàn)槭躑RL長(zhǎng)度限制灼狰,但效率較高;post可以傳輸大量數(shù)據(jù)瘫辩,所以上傳文件時(shí)只能用Post方式伏嗜;
  • get是不安全的,因?yàn)閁RL是可見(jiàn)的伐厌,可能會(huì)泄露私密信息,如密碼等裸影;post較get安全性較高挣轨;
  • get方式只能支持ASCII字符,向服務(wù)器傳的中文字符可能會(huì)亂碼轩猩。post支持標(biāo)準(zhǔn)字符集卷扮,可以正確傳遞中文字符荡澎。

4,常用的響應(yīng)碼(可以查看HttpURLConnection類(lèi)中定義的常量)

1xx:指示信息--表示請(qǐng)求已接收晤锹,繼續(xù)處理
2xx:成功--表示請(qǐng)求已被成功接收摩幔、理解、接受
3xx:重定向--要完成請(qǐng)求必須進(jìn)行更進(jìn)一步的操作
4xx:客戶(hù)端錯(cuò)誤--請(qǐng)求有語(yǔ)法錯(cuò)誤或請(qǐng)求無(wú)法實(shí)現(xiàn)
5xx:服務(wù)器端錯(cuò)誤--服務(wù)器未能實(shí)現(xiàn)合法的請(qǐng)求

200:請(qǐng)求被正常處理
204:請(qǐng)求被受理但沒(méi)有資源可以返回
206:客戶(hù)端只是請(qǐng)求資源的一部分鞭铆,服務(wù)器只對(duì)請(qǐng)求的部分資源執(zhí)行GET方法或衡,相應(yīng)報(bào)文中通過(guò)Content-Range指定范圍的資源。
301:永久性重定向
302:臨時(shí)重定向
303:與302狀態(tài)碼有相似功能车遂,只是它希望客戶(hù)端在請(qǐng)求一個(gè)URI的時(shí)候封断,能通過(guò)GET方法重定向到另一個(gè)URI上
304:發(fā)送附帶條件的請(qǐng)求時(shí),條件不滿(mǎn)足時(shí)返回舶担,與重定向無(wú)關(guān)
307:臨時(shí)重定向坡疼,與302類(lèi)似,只是強(qiáng)制要求使用POST方法
400:請(qǐng)求報(bào)文語(yǔ)法有誤衣陶,服務(wù)器無(wú)法識(shí)別
401:請(qǐng)求需要認(rèn)證
403:請(qǐng)求的對(duì)應(yīng)資源禁止被訪(fǎng)問(wèn)
404:服務(wù)器無(wú)法找到對(duì)應(yīng)資源
500:服務(wù)器內(nèi)部錯(cuò)誤
503:服務(wù)器正忙

5柄瑰,緩存機(jī)制:主要是使用header中的字段:Cache-control與ETag 來(lái)控制

Okhttp中對(duì)于網(wǎng)絡(luò)請(qǐng)求的緩存使用的就是Http自帶的的緩存機(jī)制
Volley則是自己實(shí)現(xiàn)一套緩存策略

Cache-control主要包含以及幾個(gè)字段:

  • private:則只有客戶(hù)端可以緩存
  • public:客戶(hù)端和代理服務(wù)器都可以緩存
  • max-age:緩存的過(guò)期時(shí)間
  • no-cache:需要使用對(duì)比緩存來(lái)驗(yàn)證緩存數(shù)據(jù)
  • no-store:所有內(nèi)存都不會(huì)進(jìn)行緩存

ETag:即用來(lái)進(jìn)行對(duì)比緩存,Etag是服務(wù)端資源的一個(gè)標(biāo)識(shí)碼剪况,當(dāng)客戶(hù)端發(fā)送第一次請(qǐng)求時(shí)服務(wù)端會(huì)下發(fā)當(dāng)前請(qǐng)求資源的標(biāo)識(shí)碼Etag狱意,下次再請(qǐng)求時(shí),客戶(hù)端則會(huì)通過(guò)header里的If-None-Match將這個(gè)標(biāo)識(shí)碼Etag帶上拯欧,服務(wù)端將客戶(hù)端傳來(lái)的Etag與最新的資源Etag做對(duì)比详囤,如果一樣,則表示資源沒(méi)有更新镐作,返回304藏姐。通過(guò)Cache-control和Etag的配合來(lái)實(shí)現(xiàn)Http的緩存機(jī)制。

6该贾,版本差異:

http1.1的特點(diǎn):

  • 默認(rèn)持久連接節(jié)省通信量羔杨,只要客戶(hù)端服務(wù)端任意一端沒(méi)有明確提出斷開(kāi)TCP連接,就一直保持連接杨蛋,可以發(fā)送多次HTTP請(qǐng)求(即長(zhǎng)連接)
  • 管線(xiàn)化兜材,客戶(hù)端可以同時(shí)發(fā)出多個(gè)HTTP請(qǐng)求,而不用一個(gè)個(gè)等待響應(yīng)
  • 斷點(diǎn)續(xù)傳逞力,實(shí)際上就是利用HTTP消息頭使用分塊傳輸編碼曙寡,將實(shí)體主體分塊傳輸。

http2.0特點(diǎn):

  • 二進(jìn)制格式:http1.x是文本協(xié)議寇荧,而http2.0是二進(jìn)制以幀為基本單位举庶,是一個(gè)二進(jìn)制協(xié)議,一幀中除了包含數(shù)據(jù)外同時(shí)還包含該幀的標(biāo)識(shí):Stream Identifier揩抡,即標(biāo)識(shí)了該幀屬于哪個(gè)request,使得網(wǎng)絡(luò)傳輸變得十分靈活户侥。
  • 多路復(fù)用:多個(gè)請(qǐng)求共用一個(gè)TCP連接镀琉,多個(gè)請(qǐng)求可以同時(shí)在這個(gè)TCP連接上并發(fā),一個(gè)是解決了建立多個(gè)TCP連接的消耗問(wèn)題蕊唐,一個(gè)也解決了效率的問(wèn)題屋摔。那么是什么原理支撐多個(gè)請(qǐng)求可以在一個(gè)TCP連接上并發(fā)呢?基本原理就是上面的二進(jìn)制分幀替梨,因?yàn)槊恳粠加幸粋€(gè)身份標(biāo)識(shí)钓试,所以多個(gè)請(qǐng)求的不同幀可以并發(fā)的無(wú)序發(fā)送出去,在服務(wù)端會(huì)根據(jù)每一幀的身份標(biāo)識(shí)耙替,將其整理到對(duì)應(yīng)的request中亚侠。
  • header頭部壓縮:主要是通過(guò)壓縮header來(lái)減少請(qǐng)求的大小,減少流量消耗俗扇,提高效率硝烂。
  • 支持服務(wù)端推送:服務(wù)器主動(dòng)向客戶(hù)端推送消息。

7铜幽,https : 是以安全為目標(biāo)的HTTP通道滞谢,簡(jiǎn)單講是HTTP的安全版,即HTTP+SSL除抛,HTTPS的安全基礎(chǔ)是SSL狮杨,因此加密的詳細(xì)內(nèi)容就需要SSL。使用的是非對(duì)稱(chēng)加密算法到忽。公鑰加密的信息只能用私鑰解開(kāi)橄教,而私鑰加密的信息也只能被公鑰解開(kāi)。

http與https的對(duì)比:
1喘漏,http是超文本傳輸協(xié)議护蝶,信息是明文傳輸;https則是具有安全性的ssl加密傳輸協(xié)議翩迈。
2持灰,http和https使用的是完全不同的連接方式,用的端口也不一樣负饲。前者直接運(yùn)行在TCP上堤魁,默認(rèn)端口號(hào)為80,后者運(yùn)行在SSL/TLS之上返十,SSL/TLS運(yùn)行在TCP之上妥泉,默認(rèn)端口為443。

TCP與UDP

1吧慢,TCP與UDP的區(qū)別

  • UDP面向無(wú)連接涛漂,面向報(bào)文,數(shù)據(jù)不安全检诗,速度快匈仗,不區(qū)分客戶(hù)端與服務(wù)端,最大讀取64K
  • TCP面向連接逢慌,面向字節(jié)流悠轩,數(shù)據(jù)安全,速度相應(yīng)慢攻泼,區(qū)分客戶(hù)端與服務(wù)端火架,是HTTP的底層實(shí)現(xiàn)機(jī)制。

2忙菠,TCP的三次握手與四次揮手

  • 三次握手:
    1何鸡,客戶(hù)端向服務(wù)端請(qǐng)求連接,
    2,服務(wù)端向客戶(hù)端回復(fù)收到了牛欢,此時(shí)只能證明客戶(hù)端到服務(wù)端暢通
    3骡男,客戶(hù)端收到服務(wù)端的回應(yīng),再給服務(wù)端發(fā)通知傍睹,我收到了隔盛,證明服務(wù)端到客戶(hù)端是暢通。
  • 四次揮手:
    1拾稳,客戶(hù)端發(fā)送完成后吮炕,發(fā)送數(shù)據(jù)FIN通知服務(wù)端,客戶(hù)端要關(guān)閉了
    2访得, 服務(wù)端關(guān)閉讀取數(shù)據(jù)的功能并回應(yīng)數(shù)據(jù)ACK龙亲,此時(shí)客戶(hù)端發(fā)關(guān)閉寫(xiě)的功能
    3,服務(wù)端寫(xiě)完成發(fā)送FIN通知客戶(hù)端悍抑,服務(wù)端也要關(guān)閉鳄炉,次數(shù)服務(wù)端關(guān)閉寫(xiě)的功能,
    4,客戶(hù)端收到通知后關(guān)閉讀的功能并發(fā)送ACK回應(yīng)服務(wù)端传趾。

補(bǔ)充小知識(shí):常見(jiàn)的標(biāo)識(shí)符合
SYN 是發(fā)起一個(gè)連接
ACK 是回復(fù)
RST 是重新連接
FIN 是結(jié)束連接

3迎膜,TCP的滑動(dòng)窗口協(xié)議:是保證TCP的可靠傳輸?shù)母荆驗(yàn)榘l(fā)送窗口只有收到確認(rèn)幀才會(huì)向后移動(dòng)窗口繼續(xù)發(fā)送其他幀浆兰。

  • 停止-等待協(xié)議:每發(fā)一幀都要等到確認(rèn)消息才能發(fā)送下一幀磕仅,缺點(diǎn):效率較差。
  • 后退N幀協(xié)議:采取累計(jì)確認(rèn)的方式簸呈,接收方正確的接受到N幀后發(fā)一個(gè)累計(jì)確認(rèn)消息給發(fā)送窗口榕订,確認(rèn)N幀已正確收到,如果發(fā)送方規(guī)定時(shí)間內(nèi)未收到確認(rèn)消息則認(rèn)為超時(shí)或數(shù)據(jù)丟失蜕便,則會(huì)重新發(fā)送確認(rèn)幀之后的所有幀劫恒。缺點(diǎn):出錯(cuò)序號(hào)后面的PDU已經(jīng)發(fā)送過(guò)了,但是還是要重新發(fā)送,比較浪費(fèi)两嘴。
  • 選擇重傳協(xié)議:若出現(xiàn)差錯(cuò)丛楚,只重新傳輸出現(xiàn)差錯(cuò)涉及需要的PDU,提高了傳輸效率,減少不必要的重傳憔辫。

4趣些,TCP的流量控制與擁塞控制:

  • 流量控制:是對(duì)一條通信路徑上的流量進(jìn)行控制,就是發(fā)送方通過(guò)獲取接收方的回饋來(lái)動(dòng)態(tài)調(diào)整發(fā)送的速率贰您,來(lái)達(dá)到控制流量的效果坏平,其目的是保證發(fā)送者的發(fā)送速度不超過(guò)接收者的接收速度。
  • 擁塞控制:對(duì)網(wǎng)絡(luò)中的路由和鏈路傳輸進(jìn)行速度限制锦亦,避免網(wǎng)絡(luò)過(guò)載舶替;包含四個(gè)過(guò)程:慢啟動(dòng)、擁塞避免、快重傳和快恢復(fù)
慢開(kāi)始+擁塞避免
慢開(kāi)始+快恢復(fù)

Socket通訊

Socket(套接字):本質(zhì)上是對(duì)TCP/UDP操作進(jìn)行封裝的API,從而實(shí)現(xiàn)TCP/UDP的網(wǎng)絡(luò)通訊鼠哥。特點(diǎn):
1诅岩,網(wǎng)絡(luò)上具有唯一標(biāo)識(shí)的IP地址和端口號(hào)組合在一起才能構(gòu)成唯一能識(shí)別的標(biāo)識(shí)符套接字。
2,通信的兩端都有Socket。
3,網(wǎng)絡(luò)通信其實(shí)就是Socket間的通信孵延。
4,數(shù)據(jù)在兩個(gè)Socket間通過(guò)IO流傳輸亲配。
5尘应,Socket在應(yīng)用程序中創(chuàng)建,通過(guò)一種綁定機(jī)制與驅(qū)動(dòng)程序建立關(guān)系吼虎,告訴自己所對(duì)應(yīng)的IP和port犬钢。

  • UDP通訊常用的類(lèi):
    DatagramSocket:此類(lèi)表示用來(lái)發(fā)送和接收數(shù)據(jù)報(bào)包的套接字。
    DatagramPacket:封裝的數(shù)據(jù)報(bào)文思灰,包含數(shù)據(jù)內(nèi)容玷犹,ip,端口號(hào)洒疚。
  • TCP通訊中使用的類(lèi):
    Socket:用于客戶(hù)端創(chuàng)建套接字進(jìn)行封裝目標(biāo)ip和端口號(hào)
    ServerSocket:用于服務(wù)端指定監(jiān)聽(tīng)端口歹颓。通過(guò)accept()方法獲取Scoket對(duì)象,然后進(jìn)行數(shù)據(jù)讀寫(xiě)。
//UDP發(fā)送數(shù)據(jù)(在子線(xiàn)程的run方法中執(zhí)行)
public void run() {
    DatagramSocket scoket = null;
    try {
        scoket = new DatagramSocket();
        Log.d(TAG, "run : ip1 = " + scoket.getLocalAddress().getHostName());
        InetAddress inetAddress = InetAddress.getByName(mIp);
        DatagramPacket datagramPacket = new DatagramPacket(mSendData.getBytes(), mSendData.getBytes().length, inetAddress, UDP_PORT);
        for (int i = 0; i < 3; i++) {
            Thread.sleep(100);
            Log.d(TAG, "run 11");
            scoket.send(datagramPacket);
        }
    } catch (SocketException e) {
        Log.d(TAG, "run : 111" + e.getMessage());
        e.printStackTrace();
    } catch (IOException e) {
        Log.d(TAG, "run : 211" + e.getMessage());
        e.printStackTrace();
    } catch (InterruptedException e) {
        Log.d(TAG, "run : 311" + e.getMessage());
        e.printStackTrace();
    } finally {
        closeConnection(scoket);
    }
}

//UDO接收數(shù)據(jù)
private void getUdpBack() {
    while (true) {
        DatagramSocket scoket = null;
        try {
            Thread.sleep(100);
            scoket = new DatagramSocket(UDP_PORT);
            byte[] tem = new byte[1024];
            DatagramPacket datagramPacket = new DatagramPacket(tem, tem.length);
            scoket.receive(datagramPacket);
            String hostName = datagramPacket.getAddress().getHostName();
            int port = datagramPacket.getPort();
            Log.d(TAG, "run : receive : ip = " + hostName + " ; port = " + port);
            int length = datagramPacket.getLength();
            byte[] data = new byte[length];
            System.arraycopy(datagramPacket.getData(), 0, data, 0, length);
            mUdpResult = new String(data);
            mHandler.sendEmptyMessage(UDP_BACK);
        } catch (SocketException e) {
            Log.d(TAG, "run 422: " + e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            Log.d(TAG, "run 522: " + e.getMessage());
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            closeConnection(scoket);
        }
    }
}

//關(guān)閉數(shù)據(jù)流的方法
private void closeConnection(Closeable... closeables) {
    if (closeables == null || closeables.length == 0) {
        return;
    }
    for (int i = 0; i < closeables.length; i++) {
        Closeable closeable = closeables[i];
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

//TCP客戶(hù)端發(fā)送數(shù)據(jù) (這里會(huì)出現(xiàn)Socket無(wú)法創(chuàng)建的情況油湖,可以修改端口號(hào)進(jìn)行嘗試)
public void run() {
    Socket socket = null;
    InputStream inputStream = null;
    OutputStream outputStream = null;
    try {
        //1,創(chuàng)建Socket對(duì)象,指定目標(biāo)ip與端口號(hào)
        socket = new Socket(mIp, TCP_PORT);
        inputStream = socket.getInputStream();
        String readData = readData(inputStream);
        Log.d(TAG, "run: 客戶(hù)端讀 = " + readData);
        outputStream = socket.getOutputStream();
        //2,發(fā)送數(shù)據(jù)
        outputStream.write(mSendData.getBytes());
        outputStream.flush();
        Log.d(TAG, "run: 客戶(hù)端讀 : 11");
    } catch (IOException e) {
        Log.d(TAG, "run: 客戶(hù)端讀 : 22 : " + e.getMessage());
        e.printStackTrace();
    } finally {
        //關(guān)閉流
        closeConnection(inputStream, outputStream, socket);
    }
}

/**
     * 讀取數(shù)據(jù)流
     * @param inputStream
     * @return
     */
    private String readData(InputStream inputStream) throws IOException {
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = -1;
        while ((len = inputStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }
        closeConnection(outSteam);
        return outSteam.toString();
    }

//TCP服務(wù)端接收數(shù)據(jù)
private void getTcpBack() {
    ServerSocket serverSocket = null;
    try {
        //1,構(gòu)造ServerSocket實(shí)例巍扛,指定端口監(jiān)聽(tīng)客戶(hù)端的連接請(qǐng)求
        serverSocket = new ServerSocket(TCP_PORT);
        while (true) {
            try {
                Thread.sleep(100);
                Socket accept = null;
                InputStream inputStream = null;
                OutputStream outputStream = null;
                try {
                    //2,建立跟客戶(hù)端的連接
                    accept = serverSocket.accept();
                    inputStream = accept.getInputStream();
                    outputStream = accept.getOutputStream();
                    Log.d(TAG, "getTcpBack: 11");
                    //3,讀取接收的內(nèi)容
                    mTcpResult = readData(inputStream);
                    Log.d(TAG, "getTcpBack: 22 : " + mTcpResult);
                    mHandler.sendEmptyMessage(TCP_BACK);
                } catch (IOException e) {
                    Log.d(TAG, "getTcpBack: 33 : " + e.getMessage());
                    e.printStackTrace();
                } finally {
                    //關(guān)閉流
                    closeConnection(accept, inputStream, outputStream);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        closeConnection(serverSocket);
    }
}

參考與摘錄:
https://www.cnblogs.com/sunny-sl/p/6529830.html
http://blog.chinaunix.net/uid-26275986-id-4109679.html
https://juejin.im/post/5b49f9fbf265da0f563dc9d8#heading-3

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市乏德,隨后出現(xiàn)的幾起案子撤奸,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胧瓜,死亡現(xiàn)場(chǎng)離奇詭異矢棚,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)贷痪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)幻妓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蹦误,“玉大人劫拢,你說(shuō)我怎么就攤上這事∏恳龋” “怎么了舱沧?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)偶洋。 經(jīng)常有香客問(wèn)我熟吏,道長(zhǎng),這世上最難降的妖魔是什么玄窝? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任牵寺,我火速辦了婚禮,結(jié)果婚禮上恩脂,老公的妹妹穿的比我還像新娘帽氓。我一直安慰自己,他們只是感情好俩块,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布黎休。 她就那樣靜靜地躺著,像睡著了一般玉凯。 火紅的嫁衣襯著肌膚如雪势腮。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,821評(píng)論 1 290
  • 那天漫仆,我揣著相機(jī)與錄音捎拯,去河邊找鬼。 笑死盲厌,一個(gè)胖子當(dāng)著我的面吹牛署照,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播狸眼,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼藤树,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了拓萌?” 一聲冷哼從身側(cè)響起岁钓,我...
    開(kāi)封第一講書(shū)人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后屡限,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體品嚣,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年钧大,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了翰撑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡啊央,死狀恐怖眶诈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瓜饥,我是刑警寧澤逝撬,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站乓土,受9級(jí)特大地震影響宪潮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜趣苏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一狡相、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧食磕,春花似錦、人聲如沸芬为。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)恋拷。三九已至宴偿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工遇汞, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留族檬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓换怖,卻偏偏與公主長(zhǎng)得像条摸,于是被迫代替她去往敵國(guó)和親彻坛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容