Java socket網(wǎng)絡(luò)編程

Java最初是作為網(wǎng)絡(luò)編程語言出現(xiàn)的,其對網(wǎng)絡(luò)提供了高度的支持,使得客戶端和服務(wù)器的溝通變成了現(xiàn)實(shí)置尔,而在網(wǎng)絡(luò)編程中,使用最多的就是Socket氢伟。像大家熟悉的QQ榜轿、MSN都使用了Socket相關(guān)的技術(shù)篮愉。

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

首先看下網(wǎng)絡(luò)的分層結(jié)構(gòu)和一些基本協(xié)議:


網(wǎng)絡(luò)分層協(xié)議.jpg

基于TCP/IP協(xié)議族的網(wǎng)絡(luò),被分為四層差导,分別為應(yīng)用層,傳輸層猪勇,網(wǎng)際層以及網(wǎng)絡(luò)接口層设褐,每一層都設(shè)計(jì)了相應(yīng)的協(xié)議,我們常用的一些協(xié)議(如HTTP泣刹,F(xiàn)TP等)助析,都是屬于應(yīng)用層協(xié)議,他們大多是基于傳輸層的TCP椅您,UDP設(shè)計(jì)出來的外冀。

1、兩臺(tái)計(jì)算機(jī)間進(jìn)行通訊需要以下三個(gè)條件:
IP地址掀泳、協(xié)議雪隧、端口號(hào)
2、TCP/IP協(xié)議:
是目前世界上應(yīng)用最為廣泛的協(xié)議员舵,是以TCP和IP為基礎(chǔ)的不同層次上多個(gè)協(xié)議的集合脑沿,也成TCP/IP協(xié)議族、或TCP/IP協(xié)議棧
TCP:Transmission Control Protocol 傳輸控制協(xié)議
IP:Internet Protocol 互聯(lián)網(wǎng)協(xié)議
3马僻、TCP/IP五層模型
應(yīng)用層:HTTP庄拇、FTP、SMTP韭邓、Telnet等
傳輸層:TCP/IP
網(wǎng)絡(luò)層:
數(shù)據(jù)鏈路層:
物理層:網(wǎng)線措近、雙絞線、網(wǎng)卡等
4女淑、IP地址
為實(shí)現(xiàn)網(wǎng)絡(luò)中不同計(jì)算機(jī)之間的通信瞭郑,每臺(tái)計(jì)算機(jī)都必須有一個(gè)唯一的標(biāo)識(shí)---IP地址。
32位二進(jìn)制
5鸭你、端口
區(qū)分一臺(tái)主機(jī)的多個(gè)不同應(yīng)用程序凰浮,端口號(hào)范圍為0-65535,其中0-1023位為系統(tǒng)保留苇本。
如:HTTP:80 FTP:21 Telnet:23
IP地址+端口號(hào)組成了所謂的Socket袜茧,Socket是網(wǎng)絡(luò)上運(yùn)行的程序之間雙向通信鏈路的終結(jié)點(diǎn),是TCP和UDP的基礎(chǔ)
6瓣窄、Socket套接字:
網(wǎng)絡(luò)上具有唯一標(biāo)識(shí)的IP地址和端口組合在一起才能構(gòu)成唯一能識(shí)別的標(biāo)識(shí)符套接字笛厦。
Socket原理機(jī)制:
通信的兩端都有Socket
網(wǎng)絡(luò)通信其實(shí)就是Socket間的通信
數(shù)據(jù)在兩個(gè)Socket間通過IO傳輸
7、Java中的網(wǎng)絡(luò)支持
針對網(wǎng)絡(luò)通信的不同層次俺夕,Java提供了不同的API裳凸,其提供的網(wǎng)絡(luò)功能有四大類:
InetAddress:用于標(biāo)識(shí)網(wǎng)絡(luò)上的硬件資源贱鄙,主要是IP地址
URL:統(tǒng)一資源定位符,通過URL可以直接讀取或?qū)懭刖W(wǎng)絡(luò)上的數(shù)據(jù)
Sockets:使用TCP協(xié)議實(shí)現(xiàn)的網(wǎng)絡(luò)通信Socket相關(guān)的類
Datagram:使用UDP協(xié)議姨谷,將數(shù)據(jù)保存在用戶數(shù)據(jù)報(bào)中逗宁,通過網(wǎng)絡(luò)進(jìn)行通信。

InetAddress類

InetAddress類用于標(biāo)識(shí)網(wǎng)絡(luò)上的硬件資源梦湘,標(biāo)識(shí)互聯(lián)網(wǎng)協(xié)議(IP)地址瞎颗。
該類沒有構(gòu)造方法

//獲取本機(jī)的InetAddress實(shí)例
InetAddress address =InetAddress.getLocalHost();
address.getHostName();//獲取計(jì)算機(jī)名
address.getHostAddress();//獲取IP地址
byte[] bytes = address.getAddress();//獲取字節(jié)數(shù)組形式的IP地址,以點(diǎn)分隔的四部分

//獲取其他主機(jī)的InetAddress實(shí)例
InetAddress address2 =InetAddress.getByName("其他主機(jī)名");
InetAddress address3 =InetAddress.getByName("IP地址");

URL類

1、URL(Uniform Resource Locator)統(tǒng)一資源定位符

表示Internet上某一資源的地址捌议,協(xié)議名:資源名稱

//創(chuàng)建一個(gè)URL的實(shí)例
URL baidu =new URL("http://www.baidu.com");
URL url =new URL(baidu,"/index.html?username=tom#test");//哼拔?表示參數(shù),#表示錨點(diǎn)
url.getProtocol();//獲取協(xié)議
url.getHost();//獲取主機(jī)
url.getPort();//如果沒有指定端口號(hào)瓣颅,根據(jù)協(xié)議不同使用默認(rèn)端口倦逐。此時(shí)getPort()方法的返回值為 -1
url.getPath();//獲取文件路徑
url.getFile();//文件名,包括文件路徑+參數(shù)
url.getRef();//相對路徑宫补,就是錨點(diǎn)檬姥,即#號(hào)后面的內(nèi)容
url.getQuery();//查詢字符串,即參數(shù)

2粉怕、使用URL讀取網(wǎng)頁內(nèi)容

通過URL對象的openStream()方法可以得到指定資源的輸入流穿铆,通過流能夠讀取或訪問網(wǎng)頁上的資源

//使用URL讀取網(wǎng)頁內(nèi)容
//創(chuàng)建一個(gè)URL實(shí)例
URL url =new URL("http://www.baidu.com");
InputStream is = url.openStream();//通過openStream方法獲取資源的字節(jié)輸入流
InputStreamReader isr =new InputStreamReader(is,"UTF-8");//將字節(jié)輸入流轉(zhuǎn)換為字符輸入流,如果不指定編碼,中文可能會(huì)出現(xiàn)亂碼
BufferedReader br =new BufferedReader(isr);//為字符輸入流添加緩沖斋荞,提高讀取效率
String data = br.readLine();//讀取數(shù)據(jù)
while(data!=null){
System.out.println(data);//輸出數(shù)據(jù)
data = br.readerLine();
}
br.close();
isr.colose();
is.close();

TCP編程

1荞雏、TCP協(xié)議是面向連接的、可靠的平酿、有序的凤优、以字節(jié)流的方式發(fā)送數(shù)據(jù),通過三次握手方式建立連接蜈彼,形成傳輸數(shù)據(jù)的通道筑辨,在連接中進(jìn)行大量數(shù)據(jù)的傳輸,效率會(huì)稍低
2幸逆、Java中基于TCP協(xié)議實(shí)現(xiàn)網(wǎng)絡(luò)通信的類

  • 客戶端的Socket類
  • 服務(wù)器端的ServerSocket類


    Socket通信模型.jpg

3棍辕、Socket通信的步驟

① 創(chuàng)建ServerSocket和Socket
② 打開連接到Socket的輸入/輸出流
③ 按照協(xié)議對Socket進(jìn)行讀/寫操作
④ 關(guān)閉輸入輸出流、關(guān)閉Socket

4还绘、服務(wù)器端:

① 創(chuàng)建ServerSocket對象楚昭,綁定監(jiān)聽端口
② 通過accept()方法監(jiān)聽客戶端請求
③ 連接建立后,通過輸入流讀取客戶端發(fā)送的請求信息
④ 通過輸出流向客戶端發(fā)送鄉(xiāng)音信息
⑤ 關(guān)閉相關(guān)資源

/**
 * 基于TCP協(xié)議的Socket通信拍顷,實(shí)現(xiàn)用戶登錄抚太,服務(wù)端
*/
//1、創(chuàng)建一個(gè)服務(wù)器端Socket,即ServerSocket尿贫,指定綁定的端口电媳,并監(jiān)聽此端口
ServerSocket serverSocket =newServerSocket(10086);//1024-65535的某個(gè)端口
//2、調(diào)用accept()方法開始監(jiān)聽庆亡,等待客戶端的連接
Socket socket = serverSocket.accept();
//3匾乓、獲取輸入流,并讀取客戶端信息
InputStream is = socket.getInputStream();
InputStreamReader isr =new InputStreamReader(is);
BufferedReader br =new BufferedReader(isr);
String info =null;
while((info=br.readLine())!=null){
System.out.println("我是服務(wù)器又谋,客戶端說:"+info)拼缝;
}
socket.shutdownInput();//關(guān)閉輸入流
//4、獲取輸出流搂根,響應(yīng)客戶端的請求
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.write("歡迎您!");
pw.flush();


//5铃辖、關(guān)閉資源
pw.close();
os.close();
br.close();
isr.close();
is.close();
socket.close();
serverSocket.close();

5剩愧、客戶端:

① 創(chuàng)建Socket對象,指明需要連接的服務(wù)器的地址和端口號(hào)
② 連接建立后娇斩,通過輸出流想服務(wù)器端發(fā)送請求信息
③ 通過輸入流獲取服務(wù)器響應(yīng)的信息
④ 關(guān)閉響應(yīng)資源

//客戶端
//1仁卷、創(chuàng)建客戶端Socket,指定服務(wù)器地址和端口
Socket socket =new Socket("localhost",10086);
//2犬第、獲取輸出流锦积,向服務(wù)器端發(fā)送信息
OutputStream os = socket.getOutputStream();//字節(jié)輸出流
PrintWriter pw =new PrintWriter(os);//將輸出流包裝成打印流
pw.write("用戶名:admin;密碼:123");
pw.flush();
socket.shutdownOutput();
//3歉嗓、獲取輸入流丰介,并讀取服務(wù)器端的響應(yīng)信息
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String info = null;
while((info=br.readLine())!null){
 System.out.println("我是客戶端,服務(wù)器說:"+info);
}

//4鉴分、關(guān)閉資源
br.close();
is.close();
pw.close();
os.close();
socket.close();

6哮幢、應(yīng)用多線程實(shí)現(xiàn)服務(wù)器與多客戶端之間的通信

① 服務(wù)器端創(chuàng)建ServerSocket,循環(huán)調(diào)用accept()等待客戶端連接
② 客戶端創(chuàng)建一個(gè)socket并請求和服務(wù)器端連接
③ 服務(wù)器端接受苦讀段請求志珍,創(chuàng)建socket與該客戶建立專線連接
④ 建立連接的兩個(gè)socket在一個(gè)單獨(dú)的線程上對話
⑤ 服務(wù)器端繼續(xù)等待新的連接

//服務(wù)器線程處理
//和本線程相關(guān)的socket
Socket socket =null;
//
public serverThread(Socket socket){
this.socket = socket;
}

publicvoid run(){
//服務(wù)器處理代碼
}

//============================================
//服務(wù)器代碼
ServerSocket serverSocket =new ServerSocket(10086);
Socket socket =null;
int count =0;//記錄客戶端的數(shù)量
while(true){
socket = serverScoket.accept();
ServerThread serverThread =new ServerThread(socket);
 serverThread.start();
 count++;
System.out.println("客戶端連接的數(shù)量:"+count);
}

UDP編程

UDP協(xié)議(用戶數(shù)據(jù)報(bào)協(xié)議)是無連接的橙垢、不可靠的、無序的,速度快
進(jìn)行數(shù)據(jù)傳輸時(shí)伦糯,首先將要傳輸?shù)臄?shù)據(jù)定義成數(shù)據(jù)報(bào)(Datagram)柜某,大小限制在64k,在數(shù)據(jù)報(bào)中指明數(shù)據(jù)索要達(dá)到的Socket(主機(jī)地址和端口號(hào))敛纲,然后再將數(shù)據(jù)報(bào)發(fā)送出去
DatagramPacket類:表示數(shù)據(jù)報(bào)包
DatagramSocket類:進(jìn)行端到端通信的類

1喂击、服務(wù)器端實(shí)現(xiàn)步驟

① 創(chuàng)建DatagramSocket,指定端口號(hào)
② 創(chuàng)建DatagramPacket
③ 接受客戶端發(fā)送的數(shù)據(jù)信息
④ 讀取數(shù)據(jù)

//服務(wù)器端淤翔,實(shí)現(xiàn)基于UDP的用戶登錄
//1惭等、創(chuàng)建服務(wù)器端DatagramSocket,指定端口
DatagramSocket socket =new datagramSocket(10010);
//2办铡、創(chuàng)建數(shù)據(jù)報(bào)辞做,用于接受客戶端發(fā)送的數(shù)據(jù)
byte[] data =newbyte[1024];//
DatagramPacket packet =new DatagramPacket(data,data.length);
//3琳要、接受客戶端發(fā)送的數(shù)據(jù)
socket.receive(packet);//此方法在接受數(shù)據(jù)報(bào)之前會(huì)一致阻塞
//4、讀取數(shù)據(jù)
String info =new String(data,o,data.length);
System.out.println("我是服務(wù)器秤茅,客戶端告訴我"+info);


//=========================================================
//向客戶端響應(yīng)數(shù)據(jù)
//1稚补、定義客戶端的地址、端口號(hào)框喳、數(shù)據(jù)
InetAddress address = packet.getAddress();
int port = packet.getPort();
byte[] data2 = "歡迎您课幕!".geyBytes();
//2、創(chuàng)建數(shù)據(jù)報(bào)五垮,包含響應(yīng)的數(shù)據(jù)信息
DatagramPacket packet2 = new DatagramPacket(data2,data2.length,address,port);
//3乍惊、響應(yīng)客戶端
socket.send(packet2);
//4、關(guān)閉資源
socket.close();

2放仗、客戶端實(shí)現(xiàn)步驟

① 定義發(fā)送信息
② 創(chuàng)建DatagramPacket润绎,包含將要發(fā)送的信息
③ 創(chuàng)建DatagramSocket
④ 發(fā)送數(shù)據(jù)

//客戶端
//1、定義服務(wù)器的地址诞挨、端口號(hào)莉撇、數(shù)據(jù)
InetAddress address =InetAddress.getByName("localhost");
int port =10010;
byte[] data ="用戶名:admin;密碼:123".getBytes();
//2、創(chuàng)建數(shù)據(jù)報(bào)惶傻,包含發(fā)送的數(shù)據(jù)信息
DatagramPacket packet = new DatagramPacket(data,data,length,address,port);
//3棍郎、創(chuàng)建DatagramSocket對象
DatagramSocket socket =new DatagramSocket();
//4、向服務(wù)器發(fā)送數(shù)據(jù)
socket.send(packet);


//接受服務(wù)器端響應(yīng)數(shù)據(jù)
//======================================
//1银室、創(chuàng)建數(shù)據(jù)報(bào)涂佃,用于接受服務(wù)器端響應(yīng)數(shù)據(jù)
byte[] data2 = new byte[1024];
DatagramPacket packet2 = new DatagramPacket(data2,data2.length);
//2、接受服務(wù)器響應(yīng)的數(shù)據(jù)
socket.receive(packet2);
String raply = new String(data2,0,packet2.getLenth());
System.out.println("我是客戶端蜈敢,服務(wù)器說:"+reply);
//4巡李、關(guān)閉資源
socket.close();

注意問題:

1、多線程的優(yōu)先級(jí)問題:
根據(jù)實(shí)際的經(jīng)驗(yàn)扶认,適當(dāng)?shù)慕档蛢?yōu)先級(jí)侨拦,否側(cè)可能會(huì)有程序運(yùn)行效率低的情況
2、是否關(guān)閉輸出流和輸入流:
對于同一個(gè)socket辐宾,如果關(guān)閉了輸出流狱从,則與該輸出流關(guān)聯(lián)的socket也會(huì)被關(guān)閉,所以一般不用關(guān)閉流叠纹,直接關(guān)閉socket即可
3季研、使用TCP通信傳輸對象,IO中序列化部分
4誉察、socket編程傳遞文件与涡,IO流部分

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子驼卖,更是在濱河造成了極大的恐慌氨肌,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酌畜,死亡現(xiàn)場離奇詭異怎囚,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)桥胞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門恳守,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人贩虾,你說我怎么就攤上這事催烘。” “怎么了缎罢?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵伊群,是天一觀的道長。 經(jīng)常有香客問我屁使,道長在岂,這世上最難降的妖魔是什么奔则? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任蛮寂,我火速辦了婚禮,結(jié)果婚禮上易茬,老公的妹妹穿的比我還像新娘酬蹋。我一直安慰自己,他們只是感情好抽莱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布范抓。 她就那樣靜靜地躺著,像睡著了一般食铐。 火紅的嫁衣襯著肌膚如雪匕垫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天虐呻,我揣著相機(jī)與錄音象泵,去河邊找鬼。 笑死斟叼,一個(gè)胖子當(dāng)著我的面吹牛偶惠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播朗涩,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼忽孽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起兄一,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤厘线,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后瘾腰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體皆的,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年蹋盆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了费薄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡栖雾,死狀恐怖楞抡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情析藕,我是刑警寧澤噪漾,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站夷陋,受9級(jí)特大地震影響落蝙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜治泥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一筹煮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧居夹,春花似錦败潦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至狸膏,卻和暖如春沟饥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背湾戳。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來泰國打工贤旷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人院塞。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓遮晚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拦止。 傳聞我的和親對象是個(gè)殘疾皇子县遣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

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

  • 計(jì)算機(jī)網(wǎng)絡(luò)概述 網(wǎng)絡(luò)編程的實(shí)質(zhì)就是兩個(gè)(或多個(gè))設(shè)備(例如計(jì)算機(jī))之間的數(shù)據(jù)傳輸糜颠。 按照計(jì)算機(jī)網(wǎng)絡(luò)的定義,通過一定...
    蛋炒飯_By閱讀 1,227評(píng)論 0 10
  • 網(wǎng)絡(luò)編程 網(wǎng)絡(luò)編程對于很多的初學(xué)者來說萧求,都是很向往的一種編程技能其兴,但是很多的初學(xué)者卻因?yàn)楹荛L一段時(shí)間無法進(jìn)入網(wǎng)絡(luò)編...
    程序員歐陽閱讀 2,015評(píng)論 1 37
  • 網(wǎng)絡(luò)編程的概述 網(wǎng)絡(luò)編程的實(shí)質(zhì)就是用來實(shí)現(xiàn)網(wǎng)絡(luò)互連的不同計(jì)算機(jī)上運(yùn)行的程序間可以進(jìn)行數(shù)據(jù)交換。 一.OSI網(wǎng)絡(luò)模型...
    思念揮霍閱讀 378評(píng)論 0 0
  • 1夸政、TCP為什么需要3次握手元旬,4次斷開? “三次握手”的目的是“為了防止已失效的連接請求報(bào)文段突然又傳送到了服務(wù)端...
    杰倫哎呦哎呦閱讀 3,479評(píng)論 0 6
  • 今天下午維修豐田凱美瑞 最初癥狀空調(diào)不涼 高溫 最后檢查出來是電子扇一個(gè)不轉(zhuǎn) 還有防凍液缺太多 ...
    我耳畔閱讀 107評(píng)論 0 0