第一講??? ?概述?
1、網(wǎng)絡(luò)模型:OSI參考模型和TCP/IP參考模型
圖示:
??????? 一般來(lái)說(shuō)開(kāi)發(fā)處于傳輸層和網(wǎng)際層,應(yīng)用層為:FTP和HTTP協(xié)議等,傳輸層為:UDP和TCP等,網(wǎng)際層為:IP。
??????? 通常用戶(hù)操作的是應(yīng)用層,而編程人員需要做的是傳輸層和網(wǎng)際層,用戶(hù)在應(yīng)用層操作的數(shù)據(jù),經(jīng)過(guò)逐層封包,最后到物理層發(fā)送到另一個(gè)模型中,再進(jìn)行逐層解包,圖示為:
?
2、網(wǎng)絡(luò)通信三要素:IP地址,端口號(hào),傳輸協(xié)議
A、IP地址
??????? a、它是網(wǎng)絡(luò)中的設(shè)備標(biāo)識(shí)
??????? b、不易記憶,可用主機(jī)名表示,兩者存在映射關(guān)系
??????? c、本機(jī)回環(huán)地址:127.0.0.1,主機(jī)名為:localhost。
IP地址:java中對(duì)應(yīng)的是InetAddress類(lèi),存在于java.net包中。
InetAddress類(lèi):
???? (一)無(wú)構(gòu)造函數(shù),可通過(guò)getLocalHost()方法獲取InetAddress對(duì)象,此方法是靜態(tài)的,返回本類(lèi)對(duì)象。
??????????????????InetAddress i = InetAddress.getLocalHost();
???? (二)方法:
??????????????? 1)static InetAddress getByName(String host):獲取指定主機(jī)的IP和主機(jī)名。(最好用ip地址去獲取,主機(jī)名需要解析)
??????????????? 2)static InetAddress[] getAllByName(String host):在給定主機(jī)名的情況下,根據(jù)系統(tǒng)上配置的名稱(chēng)服務(wù)返回IP地址所組成的數(shù)組。返回對(duì)象不唯一時(shí),用此方法。
??????????????? 3)String getHostAddress():返回IP地址字符串文本形式,以IP地址為主。
??????????????? 4)String getHostName():返回IP地址主機(jī)名。
???? (三)如何獲取任意一臺(tái)主機(jī)的IP地址對(duì)象:
??????????????? 1)功能:返回InetAddress對(duì)象
??????????????? 2)對(duì)于任意主機(jī),需要指定傳入主機(jī)名的參數(shù)
注意:如果IP地址和對(duì)應(yīng)的主機(jī)名,這種映射關(guān)系沒(méi)有在網(wǎng)絡(luò)上,就不會(huì)解析成功,返回的還是指定的IP。
示例:
[java]?view plaincopy
import?java.net.*;??class?IPDemo???{??????public?static?void?main(String[]?args)throws?Exception???????{??????????????????InetAddress?ia=InetAddress.getLocalHost();????????????????????????????String?address=ia.getHostAddress();??????????????????String?name=ia.getHostName();??????????System.out.println("IP="+address+"\tname="+name);????????????????????InetAddress?i=InetAddress.getByName("192.168.1.175");????????????String?add=i.getHostAddress();??????????String?na=i.getHostName();??????????System.out.println("addIP="+add+"\tiname="+na);????????????????????InetAddress[]?baidu=InetAddress.getAllByName("www.baidu.com");??????????for?(InetAddress?b?:baidu)??????????{??????????????String?baddress=b.getHostAddress();??????????????String?bname=b.getHostName();??????????????System.out.println("baiduIP="+baddress+"\tbaiduname="+bname);??????????}??????}??}?? B、端口號(hào):
??????? a、用于標(biāo)識(shí)進(jìn)程的邏輯地址,不用進(jìn)程的標(biāo)識(shí)。
??????? b、有效端口:0 ~65535,系統(tǒng)使用或保留的端口是:0~ 1024。
C、傳輸協(xié)議:
??????? 即通信規(guī)則,包含TCP和UDP協(xié)議
UDP
??????? 是面向無(wú)連接,明確了對(duì)方的端口,無(wú)論在不在網(wǎng)上,只管傳輸,不在就會(huì)丟失數(shù)據(jù)。只求速度,應(yīng)用于網(wǎng)絡(luò)視頻會(huì)議和聊天等應(yīng)用程序中。
協(xié)議特點(diǎn):
???????? a、面向無(wú)連接,即將數(shù)據(jù)及源和目的封裝成數(shù)據(jù)包中,不建立鏈接的發(fā)送
???????? b、每個(gè)數(shù)據(jù)包的大小限制在64K之內(nèi)
???????? c、因無(wú)連接,是不可靠的協(xié)議
???????? d、不建立連接,速度快。
TCP
??????? 是面向連接的,必須連接成功才能傳輸數(shù)據(jù),應(yīng)用于下載等程序上
協(xié)議特點(diǎn):
???????? a、面向連接,在建立連接后,形成傳輸數(shù)據(jù)的通道
???????? b、在連接中進(jìn)行大數(shù)據(jù)量的傳輸
?????????c、通過(guò)三次握手完成連接,是可靠的協(xié)議
???????? d、必須建立連接,效率稍慢
三次握手:第一次本方發(fā)送請(qǐng)求,第二次對(duì)方確認(rèn)連接,第三次本方再次確認(rèn)連接成功。
3、通信的步驟:
??????? 1)找到IP地址
??????? 2)數(shù)據(jù)要發(fā)送到對(duì)象指定應(yīng)用程序,為標(biāo)識(shí)這些應(yīng)用程序,所以給這些網(wǎng)絡(luò)應(yīng)用程序都用數(shù)字標(biāo)識(shí),為方便稱(chēng)呼這個(gè)數(shù)字,叫做端口,即邏輯端口。
??????? 3)定義通信規(guī)則,稱(chēng)之為協(xié)議。國(guó)際組織定義了通用協(xié)議,即TCP/IP。
注意:必須要有數(shù)字標(biāo)識(shí)才能將數(shù)據(jù)發(fā)送到應(yīng)用程序上。
?
第二講?????傳輸協(xié)議
一、Socket
??????? 1、它被稱(chēng)之為插座,相當(dāng)于港口一樣,是網(wǎng)絡(luò)服務(wù)提供的一種機(jī)制。
??????? 2、通信兩端都要有Socket,才能建立服務(wù)。
??????? 3、網(wǎng)絡(luò)通信其實(shí)就是Socket間的通信,數(shù)據(jù)在兩個(gè)Socket間通過(guò)IO傳輸。
?
二、UDP傳輸
1、通過(guò)類(lèi)DatagramSocket,此類(lèi)表示用發(fā)送和接收數(shù)據(jù)包的套接字,即Socket。
2、方法:
??????? 1)創(chuàng)建?UDPSocket發(fā)送服務(wù)對(duì)象:
????????????? DatagramSocket(),不指定端口。DatagramSocket(int port),指定端口。
??????? 2)發(fā)送:void send(DatagramPacket p)
??????? 3)接收:void receive(DatagramPacket p)
???????其中DatagramPacket:數(shù)據(jù)報(bào)包用來(lái)實(shí)現(xiàn)無(wú)連接包投遞服務(wù)的,每條報(bào)文僅根據(jù)該包中包含的信息從一臺(tái)機(jī)器路由到另一臺(tái)機(jī)器中。凡是帶地址(InetAddress)的都是用于發(fā)送包的。
3、步驟
??????? 1)發(fā)送數(shù)據(jù):
????????????? a、建立UDPSocket服務(wù),在此無(wú)需指定端口,也可以將端口加入。如果不指定的話(huà),系統(tǒng)會(huì)隨機(jī)分配一個(gè)端口,如第一次運(yùn)行時(shí)端口為1093,那么第二次就會(huì)順延為1094,再運(yùn)行會(huì)一直順延,因?yàn)橹暗亩丝谶€沒(méi)有得到釋放,所以會(huì)順延端口號(hào)值。
????????????? b、提供數(shù)據(jù),并將數(shù)據(jù)封裝到數(shù)據(jù)包中
????????????? c、通過(guò)socket服務(wù)的發(fā)送功能,將數(shù)據(jù)包發(fā)送出去
????????????? d、關(guān)閉資源
??????? 2)接收數(shù)據(jù):
????????????? a、定義UDPSocket服務(wù)。通常會(huì)監(jiān)聽(tīng)一個(gè)端口,其實(shí)就是給這個(gè)接收網(wǎng)路應(yīng)用程序定義數(shù)字標(biāo)識(shí),方便于明確哪些數(shù)據(jù)過(guò)來(lái)該應(yīng)用程序可以處理。
????????????? b、定義一個(gè)數(shù)據(jù)包,用來(lái)存儲(chǔ)接收到的字節(jié)數(shù)據(jù),因?yàn)閿?shù)據(jù)包對(duì)象中有更多功能可以提取字節(jié)數(shù)據(jù)中的不同數(shù)據(jù)信息。
????????????? c、通過(guò)socket服務(wù)的receive方法接收到的數(shù)據(jù)存入已定義好的數(shù)據(jù)包中傷感的句子
????????????? d、通過(guò)數(shù)據(jù)包對(duì)象的特有功能,將這些不同的數(shù)據(jù)取出,打印在控制臺(tái)上
??????????????e、關(guān)閉資源
????????在定義接收數(shù)據(jù)的方法中,仍會(huì)在DatagramSocket構(gòu)造函數(shù)中傳入DatagramPacket的參數(shù),這是因?yàn)槭盏降臄?shù)據(jù)太多,需要解析,通過(guò)將數(shù)據(jù)封裝成對(duì)象,易于解析,所以需要傳入?yún)?shù)。
注意:
??????? 1、發(fā)送端與接收端是兩個(gè)獨(dú)立的運(yùn)行程序。
????????2、在發(fā)送端,要在數(shù)據(jù)包對(duì)象中明確目的地IP及端口。
??????? 3、在接收端,要指定監(jiān)聽(tīng)的端口。
示例:
[java]?view plaincopy
??import?java.net.*;??class?UdpSend???{??????public?static?void?main(String[]?args)throws?Exception???????{??????????????????DatagramSocket?ds=new?DatagramSocket();??????????????????byte[]?buf="udp?shi?shen?ma".getBytes();??????????DatagramPacket?dp=new?DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.175"),10000);????????????????????ds.send(dp);??????????????????ds.close();??????}??}??????class?UdpReceive??{??????public?static?void?main(String[]?args)throws?Exception??????{????????????????????????????????????????????while(true)??????????{??????????????????????????DatagramSocket?ds=new?DatagramSocket(10000);??????????????????????????byte[]?buf=new?byte[1024];??????????????DatagramPacket?dp=new?DatagramPacket(buf,buf.length);??????????????????????????ds.receive(dp);????????????????????????String?ip=dp.getAddress().getHostName();??????????????String?data=new?String(dp.getData(),0,dp.getLength());??????????????int?port=dp.getPort();??????????????System.out.println(ip+"::"+data+"::"+port);??????????????????????????ds.close();??????????}??????????????????????}??}?? 練習(xí)一
[java]?view plaincopy
??import?java.net.*;??import?java.io.*;??class?UdpSend????{??????public?static?void?main(String[]?args)throws?Exception??????{??????????????????DatagramSocket?ds=new?DatagramSocket(9999);??????????????????DatagramPacket?dp=null;??????????BufferedReader?br=new?BufferedReader(new?InputStreamReader(System.in));??????????String?line=null;??????????while((line=br.readLine())!=null)??????????{??????????????byte[]?buf=line.getBytes();??????????????dp=new?DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.255"),10000);??????????????????????????ds.send(dp);??????????????if?("886".equals(line))??????????????{??????????????????break;??????????????}??????????}??????????????????ds.close();????????????????}??}????class?UdpReceive??{??????public?static?void?main(String[]?args)throws?Exception??????{??????????????????DatagramSocket?ds=new?DatagramSocket(10000);??????????????????while?(true)??????????{??????????????????????????byte[]?buf=new?byte[1024];??????????????DatagramPacket?dp=new?DatagramPacket(buf,buf.length);??????????????????????????ds.receive(dp);??????????????????????????String?ip=dp.getAddress().getHostAddress();??????????????String?data=new?String(dp.getData(),0,dp.getLength());??????????????int?port=dp.getPort();????????????????System.out.println("IP:"+ip+"=="+data);??????????}??????????????????????}??}????? 練習(xí)二
[java]?view plaincopy
??import?java.net.*;??import?java.io.*;????class?UdpSend?implements?Runnable??{??????????private?DatagramSocket?ds;??????UdpSend(DatagramSocket?ds)??????{??????????this.ds=ds;??????}??????????public?void?run()??????{??????????try??????????{??????????????????????????DatagramPacket?dp=null;??????????????BufferedReader?br=new?BufferedReader(new?InputStreamReader(System.in));??????????????String?line=null;??????????????while((line=br.readLine())!=null)??????????????{??????????????????byte[]?buf=line.getBytes();??????????????????dp=new?DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.255"),10000);??????????????????????????????????ds.send(dp);??????????????????if?("886".equals(line))??????????????????{??????????????????????break;??????????????????}??????????????}??????????????????????????ds.close();??????????}??????????catch?(Exception?e)??????????{??????????????throw?new?RuntimeException("發(fā)送數(shù)據(jù)失敗");??????????}?????????????}??}????class?UdpReceive?implements?Runnable??{??????????private?DatagramSocket?ds;??????UdpReceive(DatagramSocket?ds)??????{??????????this.ds=ds;??????}??????????public?void?run()??????{??????????try??????????{??????????????????????????while?(true)??????????????{??????????????????????????????????byte[]?buf=new?byte[1024];??????????????????DatagramPacket?dp=new?DatagramPacket(buf,buf.length);??????????????????????????????????ds.receive(dp);??????????????????????????????????String?ip=dp.getAddress().getHostAddress();??????????????????String?data=new?String(dp.getData(),0,dp.getLength());??????????????????int?port=dp.getPort();????????????????????System.out.println("IP:"+ip+"=="+data);??????????????}??????????????????????????????????}??????????catch?(Exception?e)??????????{??????????????throw?new?RuntimeException("接收端接收數(shù)據(jù)失敗");??????????}??????}??}????class?UdpChatDemo??{??????public?static?void?main(String[]?args)throws?Exception??????{??????????new?Thread(new?UdpSend(new?DatagramSocket())).start();??????????new?Thread(new?UdpReceive(new?DatagramSocket(10000))).start();??????}??}?? 三、TCP傳輸
1、TCP分客戶(hù)端和服務(wù)端。客戶(hù)端對(duì)應(yīng)的對(duì)象是Socket,服務(wù)端對(duì)應(yīng)的對(duì)象是ServerSocket。
2、方法:
??????? 1)創(chuàng)建客戶(hù)端對(duì)象:
??????????????Socket():創(chuàng)建空參數(shù)的客戶(hù)端對(duì)象,一般用于服務(wù)端接收數(shù)據(jù)
????????????? Socket(String host,int port),指定要接收的IP地址和端口號(hào)淘寶開(kāi)店
??????? 2)創(chuàng)建服務(wù)端對(duì)象:ServerSocket(int port):指定接收的客戶(hù)端的端口
??????? 3)Socket accept():監(jiān)聽(tīng)并接受到此套接字的連接
??????? 4)void shutdownInput():此套接字的輸入流至于“流的末尾”
??????? 5)void shutdownOutput():禁用此套接字的輸出流
??????? 6)InputStream getInputStream():返回此套接字的輸入流,Socket對(duì)象調(diào)用
??????? 7)OutputStream getOutputStream():返回套接字的輸出流,Socket對(duì)象調(diào)用
3、基本思路
客戶(hù)端:
??????? 1)客戶(hù)端需要明確服務(wù)器的ip地址以及端口,這樣才可以去試著建立連接,如果連接失敗,會(huì)出現(xiàn)異常。
??????? 2)連接成功,說(shuō)明客戶(hù)端與服務(wù)端建立了通道,那么通過(guò)IO流就可以進(jìn)行數(shù)據(jù)的傳輸,而Socket對(duì)象已經(jīng)提供了輸入流和輸出流對(duì)象,通過(guò)getInputStream(),getOutputStream()獲取即可。
??????? 3)與服務(wù)端通訊結(jié)束后,關(guān)閉Socket。
服務(wù)端:
??????? 1)服務(wù)端需要明確它要處理的數(shù)據(jù)是從哪個(gè)端口進(jìn)入的。
??????? 2)當(dāng)有客戶(hù)端訪(fǎng)問(wèn)時(shí),要明確是哪個(gè)客戶(hù)端,可通過(guò)accept()獲取已連接的客戶(hù)端對(duì)象,并通過(guò)該對(duì)象與客戶(hù)端通過(guò)IO流進(jìn)行數(shù)據(jù)傳輸。
??????? 3)當(dāng)該客戶(hù)端訪(fǎng)問(wèn)結(jié)束,關(guān)閉該客戶(hù)端。
4、步驟
客戶(hù)端:
??????? 通過(guò)查閱Socket對(duì)象的API文檔,發(fā)現(xiàn)在該對(duì)象在建立時(shí),就可去連接指定主機(jī),因?yàn)門(mén)CP是面向連接的,所以在建立Socket服務(wù)時(shí),就要有服務(wù)端存在,并連接成功,形成通路后,再通過(guò)該通道進(jìn)行數(shù)據(jù)的傳輸。
?????????1)創(chuàng)建Socket服務(wù),并指定要連接的主機(jī)端口。通路一建立,就會(huì)產(chǎn)生Socket流(包括輸入流和輸出流),通過(guò)方法獲取
???????? 2)為了發(fā)送數(shù)據(jù),應(yīng)獲取Socket中的輸出流,如果要接收服務(wù)端的反饋信息,還需要獲取Socket的輸入流
???????? 3)通過(guò)輸出流的write()方法將要發(fā)送的數(shù)據(jù)寫(xiě)入到流中
???????? 4)關(guān)閉Socket流資源
服務(wù)端:
??????? 服務(wù)器套接字等待請(qǐng)求通過(guò)網(wǎng)絡(luò)傳入。它基于該請(qǐng)求執(zhí)行某些操作,然后可能向請(qǐng)求者返回結(jié)果。需監(jiān)聽(tīng)一個(gè)端口。
?????????1)建立服務(wù)端的Socket服務(wù),并監(jiān)聽(tīng)一個(gè)端口。通過(guò)ServerSocet帶端口參數(shù)的構(gòu)造函數(shù)
???????? 2)獲取連接過(guò)來(lái)的客戶(hù)對(duì)象,通過(guò)ServerSocket的accept()方法,此方法是阻塞式的,如果服務(wù)端沒(méi)有連接到就會(huì)一直等待
???????? 3)客戶(hù)端如果發(fā)過(guò)來(lái)數(shù)據(jù),則服務(wù)端要使用對(duì)應(yīng)的客戶(hù)端對(duì)象,并獲取到該客戶(hù)端對(duì)象的讀取流讀取發(fā)過(guò)來(lái)的數(shù)據(jù),并輸出到指定目的地。
???????? 4)關(guān)閉服務(wù)端(可選)。一般服務(wù)端是常開(kāi)的,因?yàn)樵趯?shí)際應(yīng)用中,隨時(shí)有客戶(hù)端在請(qǐng)求連接和服務(wù)。但這里需要定時(shí)關(guān)閉客戶(hù)端對(duì)象流,避免某一個(gè)客戶(hù)端長(zhǎng)時(shí)間占用服務(wù)器端。
示例:
[java]?view plaincopy
import?java.net.*;??import?java.io.*;??class??TcpClient??{??????public?static?void?main(String[]?args)?throws?Exception??????{??????????????????Socket?s=new?Socket("127.0.0.1",10000);??????????????????OutputStream?out=s.getOutputStream();??????????out.write("你好!".getBytes());??????????????????InputStream?in=s.getInputStream();????????????????????byte[]?buf=new?byte[1024];??????????int?len=in.read(buf);??????????????????System.out.println(new?String(buf,0,len));????????????s.close();????}??}????????class?TcpServer??{??????public?static?void?main(String[]?args)throws?Exception??????{??????????????????ServerSocket?ss=new?ServerSocket(10000);??????????????????Socket?s=ss.accept();??????????????????String?ip=s.getInetAddress().getHostName();??????????System.out.println(ip+"connected....");??????????????????InputStream?in=s.getInputStream();??????????byte[]?buf=new?byte[1024];??????????int?len=in.read(buf);??????????System.out.println(new?String(buf,0,len));????????????????????OutputStream?out=s.getOutputStream();??????????out.write("哥們,收到!".getBytes());????????????????????s.close();??????????ss.close();????}??}?? 練習(xí)一
[java]?view plaincopy
??import?java.io.*;??import?java.net.*;??class??TcpClient??{??????public?static?void?main(String[]?args)?throws?Exception??????{??????????????????Socket?s=new?Socket("127.0.0.1",10000);????????????????????????????BufferedReader?br=new?BufferedReader(new?InputStreamReader(System.in));????????????????????????????????????PrintWriter?pw=new?PrintWriter(s.getOutputStream(),true);????????????????????????????BufferedReader?brin=new?BufferedReader(new?InputStreamReader(s.getInputStream()));????????????String?line=null;??????????while?((line=br.readLine())!=null)??????????{????????????????????????????if("over".equals(line))??????????????????break;????????????????????????????????????????????????????pw.println(line);??????????????String?data=brin.readLine();????????????System.out.println(data);????????????}??????????br.close();????????s.close();??????}??}????class?TcpServer??{??????public?static?void?main(String[]?args)throws?Exception??????{??????????????????ServerSocket?ss?=new?ServerSocket(10000);????????????????????????????Socket?s=ss.accept();????????????????????System.out.println(s.getInetAddress().getHostName()+"?connected.......");????????????????????BufferedReader?brin=new?BufferedReader(new?InputStreamReader(s.getInputStream()));????????????????????????????PrintWriter?pw=new?PrintWriter(s.getOutputStream(),true);????????????String?line=null;??????????while?((line=brin.readLine())!=null)??????????{??????????????System.out.println(line);??????????????????????????????????????????????????????pw.println(line.toUpperCase());????????}??????????s.close();????????ss.close();關(guān)閉資源(可選)??????}??}?? 練習(xí)二
[java]?view plaincopy
??import?java.io.*;??import?java.net.*;??????class??TcpClient??{??????public?static?void?main(String[]?args)?throws?Exception??????{??????????????????Socket?s=new?Socket("127.0.0.1",10000);????????????????????????????BufferedReader?br=new?BufferedReader(new?FileReader("TcpDemo.java"));????????????????????????????PrintWriter?pw=new?PrintWriter(s.getOutputStream(),true);????????????????????BufferedReader?brin=new?BufferedReader(new?InputStreamReader(s.getInputStream()));????????????String?line=null;??????????while?((line=br.readLine())!=null)??????????{??????????????pw.println(line);??????????}????????????????????s.shutdownOutput();??????????System.out.println(brin.readLine());??????????????????br.close();??????????s.close();??????}??}????class?TcpServer??{??????public?static?void?main(String[]?args)throws?Exception??????{??????????????????ServerSocket?ss?=new?ServerSocket(10000);????????????????????????????Socket?s=ss.accept();????????????????????System.out.println(s.getInetAddress().getHostName()+"?connected.......");????????????????????BufferedReader?brin=new?BufferedReader(new?InputStreamReader(s.getInputStream()));????????????????????PrintWriter?out=new?PrintWriter(new?FileWriter("TcpDemo.txt"),true);????????????????????????????BufferedWriter?bwout=new?BufferedWriter(new?OutputStreamWriter(s.getOutputStream()));????????????String?line=null;??????????while?((line=brin.readLine())!=null)??????????{??????????????out.println(line);??????????}??????????????????????????????????????bwout.write("上傳成功!");??????????bwout.newLine();????????bwout.flush();??????????out.close();????????s.close();??????????ss.close();??????}??}?? ?
第三講?????應(yīng)用
一、用TCP客戶(hù)端并發(fā)上傳圖片
1、一對(duì)一(單線(xiàn)程)上傳的思路:
客戶(hù)端
??????? a、服務(wù)端點(diǎn)。
??????? b、讀取客戶(hù)端已有的圖片數(shù)據(jù)
??????? c、通過(guò)Socket輸出流將數(shù)據(jù)發(fā)給服務(wù)端
??????? d、讀取服務(wù)端反饋信息。
??????? e、關(guān)閉
服務(wù)端
?????? ?a、服務(wù)端服務(wù),并監(jiān)聽(tīng)窗口
??????? b、獲取客戶(hù)端對(duì)象,并獲取客戶(hù)ip
??????? c、讀取客戶(hù)端輸入流數(shù)據(jù)
??????? d、寫(xiě)入文件
??????? e、用客戶(hù)端輸出流反饋信息
??????? f、關(guān)流
2、單線(xiàn)程的服務(wù)端有個(gè)局限性。當(dāng)A客戶(hù)端連接上以后,被服務(wù)端獲取到。服務(wù)端執(zhí)行具體流程。這時(shí)B客戶(hù)端連接,只能等待。因?yàn)榉?wù)端還沒(méi)有處理完A客戶(hù)端的請(qǐng)求。還沒(méi)有循環(huán)回來(lái)執(zhí)行下一次accept方法。所以,暫時(shí)獲取不到B客戶(hù)端對(duì)象。
??????? 那么為了可以讓多個(gè)客戶(hù)端同時(shí)并發(fā)訪(fǎng)問(wèn)服務(wù)端。服務(wù)端最好就是將每個(gè)客戶(hù)端封裝到一個(gè)單獨(dú)的線(xiàn)程中,這樣,就可以同時(shí)處理多個(gè)客戶(hù)端請(qǐng)求。
如何定義線(xiàn)程呢?
??????? 只要明確了每一個(gè)客戶(hù)端要在服務(wù)端執(zhí)行的代碼,將該代碼存入run方法即可。
代碼:
[java]?view plaincopy
??import?java.io.*;??import?java.net.*;??class??PicClient??{??????public?static?void?main(String[]?args)?throws?Exception??????{??????????????????if?(args.length!=1)??????????{??????????????System.out.println("請(qǐng)指定一個(gè)圖片文件!");??????????????return;??????????}????????????File?file=new?File(args[0]);????????????????????if?(!(file.exists()&&file.isFile()))??????????{??????????????System.out.println("你上傳的文件有問(wèn)題,非文件或者不存在!");??????????????return;??????????}????????????????????if?(!file.getName().endsWith(".jpg"))??????????{??????????????System.out.println("圖片格式錯(cuò)誤,請(qǐng)重新選擇!");??????????????return;??????????}????????????????????if?(file.length()>1024*1024*5)??????????{??????????????System.out.println("你上傳的文件過(guò)大,居心叵測(cè)!");??????????????return;??????????}????????????????????Socket?s=new?Socket("localhost",10000);??????????????????FileInputStream?fis=new?FileInputStream(file);????????????????????????????OutputStream?out?=s.getOutputStream();????????????BufferedReader?in=new?BufferedReader(new?InputStreamReader(s.getInputStream()));????????????byte[]?buf=new?byte[1024];????????????int?len=0;????????????while?((len=fis.read(buf))!=-1)??????????{??????????????out.write(buf,0,len);??????????}????????????????????s.shutdownOutput();????????????String?info=in.readLine();????????System.out.println(info);????????????fis.close();????????s.close();????????}??}????class?PicServer??{??????public?static?void?main(String[]?args)throws?Exception??????{??????????????????ServerSocket?ss=new?ServerSocket(10000);????????????????????while?(true)??????????{??????????????????????????Socket?s=ss.accept();??????????????????????????new?Thread(new?PicThread(s)).start();??????????}????????????????????????}??}????class?PicThread?implements?Runnable??{??????private?Socket?s;??????PicThread(Socket?s)??????{??????????this.s=s;??????}??????public?void?run()??????{??????????int?count=1;??????????????????String?ip=s.getInetAddress().getHostAddress();??????????try??????????{?????????????????????System.out.println(ip+"??connected.....");????????????????????????????InputStream?in=s.getInputStream();??????????????????????????File?dir?=new?File("C:\\Users\\asus\\Desktop");??????????????????????????File?file=new?File(dir,ip+".jpg");??????????????????????????while(file.exists())??????????????{??????????????????file=new?File(dir,ip+"("+(count++)+").jpg");??????????????}????????????????????????????FileOutputStream?fos=new?FileOutputStream(file);????????????????byte[]?buf=new?byte[1024];??????????????int?len=0;??????????????while?((len=in.read(buf))!=-1)??????????????{??????????????????fos.write(buf,0,len);??????????????}????????????????????????????OutputStream?out=s.getOutputStream();????????????????????????????out.write("上傳成功!".getBytes());????????????????fos.close();????????????s.close();??????????}??????????catch?(Exception?e)??????????{??????????????throw?new?RuntimeException(ip+"圖片上傳失敗");??????????}??????}??}??
二、客戶(hù)端并發(fā)登錄
????????客戶(hù)端通過(guò)鍵盤(pán)錄入用戶(hù)名,服務(wù)端對(duì)這個(gè)用戶(hù)名進(jìn)行校驗(yàn)。
??????? 如果該用戶(hù)存在,在服務(wù)端顯示xxx,已登陸;并在客戶(hù)端顯示xxx,歡迎光臨。
??????? 如果用戶(hù)不存在,在服務(wù)端顯示xxx,嘗試登陸;并在客戶(hù)端顯示xxx,該用戶(hù)不存在。
??????? 最多就登錄三次。
代碼:?
[java]?view plaincopy
import?java.io.*;??import?java.net.*;??class??LoginClient??{??????public?static?void?main(String[]?args)?throws?Exception??????{??????????????????Socket?s=new?Socket("localhost",10000);??????????????????BufferedReader?br=new?BufferedReader(new?InputStreamReader(System.in));??????????????????????????????PrintWriter?out?=new?PrintWriter(s.getOutputStream(),true?);????????????????????BufferedReader?in=new?BufferedReader(new?InputStreamReader(s.getInputStream()));????????????String?line=null;????????????for(int?x=0;x<3;x++)??????????{??????????????line=br.readLine();????????????if?(line==null)??????????????{??????????????????break;????????????}????????????????out.println(line);??????????????String?info=in.readLine();??????????????System.out.println(info);????????????????if?(info.contains("歡迎"))????????????{??????????????????break;????????????}??????????}????????????br.close();????????s.close();??????}??}????class?LoginServer??{??????public?static?void?main(String?[]?args)throws?Exception??????{??????????????????ServerSocket?ss=new?ServerSocket(10000);????????????????????while?(true)??????????{??????????????????????????Socket?s=ss.accept();????????????????????????????????????new?Thread(new?LoginThread(s)).start();??????????}????????????????????????}??}????class?LoginThread?implements?Runnable??{??????private?Socket?s;??????LoginThread(Socket?s)??????{??????????this.s=s;??????}??????public?void?run()??????{??????????????????String?ip=s.getInetAddress().getHostAddress();??????????System.out.println(ip+"??connected.....");??????????try??????????{?????????????????????for?(int?x=0;x<3?;x++?)??????????????{?????????????????????????????????????BufferedReader?in=new?BufferedReader(new?InputStreamReader(s.getInputStream()));????????????????????????????????????????????????????BufferedReader?br=new?BufferedReader(new?FileReader("users.txt"));????????????????????String?line=in.readLine();????????????????if?(line==null)????????????????{??????????????????????break;????????????????}??????????????????String?data=null;??????????????????boolean?flag=false;????????????????????????????????while?((data=br.readLine())!=null)??????????????????{??????????????????????if?(line.equals(data))??????????????????????{??????????????????????????flag=true;????????????????????????break;??????????????????????}??????????????????}????????????????????????????????????PrintWriter?out=new?PrintWriter(s.getOutputStream(),true);????????????????????if?(flag)??????????????????{??????????????????????System.out.println(line+",已登陸!");????????????????????????????????????????????out.println(line+",歡迎光臨!");????????????????????????break;????????????????}??????????????????else??????????????????{??????????????????????System.out.println(line+",嘗試登陸!");??????????????????????out.println(line+",用戶(hù)名不存在!");??????????????????}?????????????????}??????????????s.close();????????}??????????catch?(Exception?e)??????????{??????????????throw?new?RuntimeException("用戶(hù)登陸失敗");??????????}?????????}??}??
三、客戶(hù)端和服務(wù)的瀏覽器演示
??????? 瀏覽器是一個(gè)標(biāo)準(zhǔn)的客戶(hù)端,它可以對(duì)服務(wù)端傳送過(guò)來(lái)的數(shù)據(jù)消息進(jìn)行解析,把符合應(yīng)用層協(xié)議的消息部分解析后,將頭信息拆包掉,傳送到應(yīng)用層,只保留了正確的正文主題部分顯示在主體部分上。
??????? 而由于使用java編譯是在傳輸層和網(wǎng)際層處理的,所以,會(huì)接受到全部的消息,包含了頭消息。而瀏覽器處于應(yīng)用層,已將發(fā)送來(lái)的頭消息去除,只留下了主體信息。
示例:
??????? 自定義服務(wù)器,用瀏覽器訪(fǎng)問(wèn):
[java]?view plaincopy
import?java.io.*;??import?java.net.*;????class??ServerDemo??{??????public?static?void?main(String[]?args)throws?Exception???????{??????????????????ServerSocket?ss=new?ServerSocket(10000);??????????????????Socket?s=ss.accept();??????????????????String?ip=s.getInetAddress().getHostAddress();????????????System.out.println(ip);??????????????????InputStream?in=s.getInputStream();????????????byte[]?buf=new?byte[1024];??????????int?len=in.read(buf);??????????????????System.out.println(new?String(buf,0,len));??????????????????PrintWriter?out=new?PrintWriter(s.getOutputStream(),true);??????????out.println("<font?color='red'?size='7'>客戶(hù)端你好!</font>");????????????s.close();????????ss.close();??????}??}?? ?
四、URL和URLConnection
1、URL:
??????? URI:范圍更大,條形碼也包含于此范圍
??????? URL:范圍較小,即域名
方法:
??????? 1)構(gòu)造函數(shù):URL(String protocol,String host,int port,String file);//根據(jù)指定?protocol、host、port號(hào)和?file?創(chuàng)建?URL對(duì)象。
??????? 2)String getProtocol();//獲取協(xié)議名稱(chēng)
??????? 3)String getHost();//獲取主機(jī)名
??????? 4)int getPort();//獲取端口號(hào)
??????? 5)String getFile();//獲取URL文件名
??????? 6)String getPath();//獲取此URL的路徑部分
??????? 7)String getQuery();//獲取此URL的查詢(xún)部,客戶(hù)端傳輸?shù)奶囟ㄐ畔?/p>
注:一般輸入網(wǎng)址,是不帶端口號(hào)的,此時(shí)可進(jìn)行獲取,通過(guò)獲取網(wǎng)址返回的port,若port為-1,則分配一個(gè)默認(rèn)的80端口,如
??????? int port = getPort();
??????? if(port == -1)
????????????? port = 80;
2、URLConnection
方法:
??????? 1)URLConnection openConnection();//用URL調(diào)用此方法,返回一個(gè)?URLConnection?對(duì)象,它表示到?URL?所引用的遠(yuǎn)程對(duì)象的連接。
??????? 2)InputStream getInputStream();//獲取輸入流
??????? 3)OutputStream getOutputStream();//獲取輸出流
示例:
[java]?view plaincopy
??import?java.io.*;??import?java.awt.*;??import?java.awt.event.*;??import?java.net.*;????class?MyIEGUIDemo??{??????????private?Frame?f;??????private?Button?but,bok;??????private?TextField?tf;??????private?TextArea?ta;????????????MyIEGUIDemo()??????{??????????init();??????}????????????public?void?init()??????{??????????????????f=new?Frame("我的Window");??????????but=new?Button("跳轉(zhuǎn)");??????????tf=new?TextField(50);??????????ta=new?TextArea(25,60);????????????????????f.setBounds(300,150,500,500);??????????f.setLayout(new?FlowLayout());????????????????????f.add(tf);??????????f.add(but);??????????f.add(ta);????????????????????myEvent();????????????????????f.setVisible(true);??????}????????????public?void?myEvent()??????{??????????????????f.addWindowListener(new?WindowAdapter()??????????{??????????????public?void?windowClosing(WindowEvent?e)??????????????{??????????????????System.exit(0);??????????????}??????????});????????????????????but.addActionListener(new?ActionListener()??????????{??????????????public?void?actionPerformed(ActionEvent?e)??????????????{??????????????????showFile();????????????}??????????});????????????????????????????????tf.addKeyListener(new?KeyAdapter()??????????{??????????????public?void?keyPressed(KeyEvent?e)??????????????{??????????????????????????????????if(e.getKeyCode()==KeyEvent.VK_ENTER)??????????????????????showFile();??????????????}??????????});??????}????????????????private?void?showFile()??????????{??????????????ta.setText("");??????????????String?path=tf.getText();????????????try??????????????{??????????????????URL?url?=new?URL(path);??連接網(wǎng)頁(yè)服務(wù)器??????????????????URLConnection?conn=url.openConnection();??????????????????????????????????InputStream?in=conn.getInputStream();????????????????????byte[]?buf=new?byte[1024*1024];????????????????????int?len=in.read(buf);??????????????????????????????????ta.append(new?String(buf,0,len));??????????????}??????????????catch?(Exception?e)??????????????{??????????????????throw?new?RuntimeException("連接"+path+"網(wǎng)站失敗");??????????????}??????????}????????public?static?void?main(String[]?args)???????{??????????????????new?MyIEGUIDemo();??????}??}?? ?
小知識(shí)點(diǎn)
1、Socket類(lèi)的構(gòu)造函數(shù)中,有一個(gè)空參數(shù)的構(gòu)造函數(shù):
??????? Socket()//通過(guò)系統(tǒng)默認(rèn)類(lèi)型的?SocketImpl創(chuàng)建未連接套接字對(duì)象
???????可以通過(guò)connect(SocketAddress endpoint)方法來(lái)連接服務(wù)器。而SocketAddress是一個(gè)抽象類(lèi),它的子類(lèi)InetSocketAddress實(shí)現(xiàn)了IP套接字地址(IP地址+端口號(hào))。所以就可以連接到服務(wù)器了。
2、ServerSocket對(duì)象中的構(gòu)造函數(shù):
??????? ServerSocket(int port,int backlog),其中的backlog表示隊(duì)列的最大長(zhǎng)度,即最多連入客戶(hù)端的個(gè)數(shù),即最大連接數(shù)。
3、在瀏覽器輸入網(wǎng)址訪(fǎng)問(wèn)一臺(tái)主機(jī)所做的操作:
???????如輸入http://61.135.169.125,可以直接連接此ip的主機(jī),而我們一般是輸入主機(jī)名:http:/www.baidu.ocm(百度主機(jī)對(duì)應(yīng)的ip地址就是:61.135.169.125),那么此時(shí)瀏覽器做了神馬操作呢?
?????? 也就是說(shuō)如何通過(guò)主機(jī)名獲取IP地址,從而連接到這臺(tái)主機(jī)呢?這就需要將主機(jī)名翻譯成IP地址,即域名解析:DNS
????????在進(jìn)行訪(fǎng)問(wèn)的時(shí)候,會(huì)先在本地的hosts文件(c:\windows\system32\drivers\ext\host)中找對(duì)應(yīng)的映射。若有,則直接返回請(qǐng)求;若無(wú),則到公網(wǎng)的映射列表即DNS中找對(duì)應(yīng)的映射,找到后,將主機(jī)名對(duì)應(yīng)的IP地址返回給本機(jī),本機(jī)通過(guò)這個(gè)IP地址找到對(duì)應(yīng)的服務(wù)器。
示意圖:
?host應(yīng)用:可屏蔽一些惡意網(wǎng)址,即將對(duì)應(yīng)的映射關(guān)系寫(xiě)入hosts中,將IP地址改為本機(jī)的回環(huán)地址,那么會(huì)直接找到hosts,就不會(huì)將請(qǐng)求發(fā)送出去了。
?
轉(zhuǎn)載于:https://www.cnblogs.com/tiankong101/p/4227355.html
總結(jié)
以上是生活随笔為你收集整理的Java基础---网络编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。