1.
什么是
TCP/ IP
協議?
2. TCP/IP
有哪兩種傳輸協議
,
各有什么特點?
3.
什么是
URL
?
4. URL
和
IP
地址有什么樣的關系?
5.
什么叫套接字(
Socket
)?
6.
套接字(
Socket
)和
TCP/IP
協議的關系?
7. URL
和套接字(
Socket
)的關系?
8.1 網絡編程基本概念,TCP/IP協議簡介
8.1.1 網絡基礎知識
網絡編程的目的就是指直接或間接地通過網絡協議與其他計算機進行通訊。網絡編程中有兩個主要的問題,一個是如何準確的定位網絡上一臺或多臺主機,另一個就是找到主機后如何可靠高效的進行數據傳輸。在
TCP/IP
協議中
IP
層主要負責網絡主機的定位,數據傳輸的路由,由
IP
地址可以唯一地確定
Internet
上的一臺主機。而
TCP
層則提供面向應用的可靠的或非可靠的數據傳輸機制,這是網絡編程的主要對象,一般不需要關心
IP
層是如何處理數據的。
目前較為流行的網絡編程模型是客戶機
/
服務器(
C/S
)結構。即通信雙方一方作為服務器等待客戶提出請求并予以響應。客戶則在需要服務時向服務器提出申請。服務器一般作為守護進程始終運行,監聽網絡端口,一旦有客戶請求,就會啟動一個服務進程來響應該客戶,同時自己繼續監聽服務端口,使后來的客戶也能及時得到服務。
8.1.3兩類傳輸協議:TCP;UDP
盡管
TCP/IP
協議的名稱中只有
TCP
這個協議名,但是在
TCP/IP
的傳輸層同時存在
TCP
和
UDP
兩個協議。
TCP
是
Tranfer Control Protocol
的簡稱,是一種面向連接的保證可靠傳輸的協議。
通過
TCP
協議傳輸,得到的是一個順序的無差錯的數據流。發送方和接收方的成對的兩個
socket
之間必須建立連接,以便在
TCP
協議的基礎上進行通信,當一個
socket
(通常都是
server socket
)等待建立連接時,另一個
socket
可以要求進行連接,一旦這兩個
socket
連接起來,它們就可以進行雙向數據傳輸,雙方都可以進行發送或接收操作。
UDP
是
User Datagram Protocol
的簡稱,是一種無連接的協議,
每個數據報都是一個獨立的信息,包括完整的源地址或目的地址,它在網絡上以任何可能的路徑傳往目的地,因此能否到達目的地,到達目的地的時間以及內容的正確性都是不能被保證的。
下面我們對這兩種協議做簡單比較:
使用
UDP
時,每個數據報中都給出了完整的地址信息,因此無需要建立發送方和接收方的連接。對于
TCP
協議,由于它是一個面向連接的協議,在
socket
之間進行數據傳輸之前必然要建立連接,所以在
TCP
中多了一個連接建立的時間。
?
使用
UDP
傳輸數據時是有大小限制的,每個被傳輸的數據報必須限定在
64KB
之內。而
TCP
沒有這方面的限制,一旦連接建立起來,雙方的
socket
就可以按統一的格式傳輸大量的數據。
UDP
是一個不可靠的協議,發送方所發送的數據報并不一定以相同的次序到達接收方。而
TCP
是一個可靠的協議,它確保接收方完全正確地獲取發送方所發送的全部數據。
總之,
TCP
在網絡通信上有極強的生命力,例如遠程連接(
Telnet
)和文件傳輸(
FTP
)都需要不定長度的數據被可靠地傳輸。相比之下
UDP
操作簡單,而且僅需要較少的監護,因此通常用于局域網高可靠性的分散系統中
client/server
應用程序。
讀者可能要問,既然有了保證可靠傳輸的
TCP
協議,為什么還要非可靠傳輸的
UDP
協議呢?主要的原因有兩個。一是可靠的傳輸是要付出代價的,對數據內容正確性的檢驗必然占用計算機的處理時間和網絡的帶寬,因此
TCP
傳輸的效率不如
UDP
高。二是在許多應用中并不需要保證嚴格的傳輸可靠性,比如視頻會議系統,并不要求音頻視頻數據絕對的正確,只要保證連貫性就可以了,這種情況下顯然使用
UDP
會更合理一些。
8.2 基于URL的高層次Java網絡編程
8.2.1一致資源定位器URL
URL(Uniform Resource Locator)
是一致資源定位器的簡稱,它表示
Internet
上某一資源的地址。通過
URL
我們可以訪問
Internet
上的各種網絡資源,比如最常見的
WWW
,
FTP
站點。瀏覽器通過解析給定的
URL
可以在網絡上查找相應的文件或其他資源。
8.2.2 URL的組成
protocol://resourceName
協議名(
protocol
)指明獲取資源所使用的傳輸協議,如
http
、
ftp
、
gopher
、
file
等,資源名(
resourceName
)則應該是資源的完整地址,包括主機名、端口號、文件名或文件內部的一個引用。
例如:
http://www.sun.com/
協議名
://
主機名
http://home.netscape.com/home/welcome.html
協議名
://
機器名+文件名
http://www.gamelan.com:80/Gamelan/network.html#BOTTOM
協議名
://
機器名+端口號+文件名+內部引用
.
8.2.3 創建一個URL
為了表示
URL, java.net中實現了類URL。我們可以通過下面的構造方法來初始化一個URL對象:
?。?) public URL (String spec);
通過一個表示URL地址的字符串可以構造一個URL對象。
URL urlBase=new URL("http://www. 263.net/")
?。?) public URL(URL context, String spec);
通過基URL和相對URL構造一個URL對象。
URL net263=new URL ("http://www.263.net/");
URL index263=new URL(net263, "index.html")
?。?) public URL(String protocol, String host, String file);
new URL("http", "www.gamelan.com", "/pages/Gamelan.net. html");
(4) public URL(String protocol, String host, int port, String file);
URL gamelan=new URL("http", "www.gamelan.com", 80, "Pages/Gamelan.network.html");
注意:類URL的構造方法都聲明拋棄非運行時例外(MalformedURLException),因此生成URL對象時,我們必須要對這一例外進行處理,通常是用try-catch語句進行捕獲。格式如下:
try{
URL myURL= new URL(…)
}catch (MalformedURLException e){
…
}
8.2.4 解析一個URL
一個URL對象生成后,其屬性是不能被改變的,但是我們可以通過類URL所提供的方法來獲取這些屬性:
public String getProtocol() 獲取該URL的協議名。
public String getHost() 獲取該URL的主機名。
public int getPort() 獲取該URL的端口號,如果沒有設置端口,返回-1。
public String getFile() 獲取該URL的文件名。
public String getRef() 獲取該URL在文件中的相對位置。
public String getQuery() 獲取該URL的查詢信息。
public String getPath() 獲取該URL的路徑
public String getAuthority() 獲取該URL的權限信息
public String getUserInfo() 獲得使用者的信息
public String getRef()
獲得該
URL
的錨
8.2.5 從URL讀取WWW網絡資源
當我們得到一個
URL
對象后,就可以通過它讀取指定的
WWW
資源。這時我們將使用
URL
的方法
openStream()
,其定義為:
InputStream openStream();
方法
openSteam()
與指定的
URL
建立連接并返回
InputStream
類的對象以從這一連接中讀取數據。
public class URLReader {
public static void main(String[] args) throws Exception {
//
聲明拋出所有例外
URL tirc = new URL("http://www.tirc1.cs.tsinghua.edu.cn/");
//
構建一
URL
對象
BufferedReader in = new BufferedReader(new InputStreamReader(tirc.openStream()));
//
使用
openStream
得到一輸入流并由此構造一個
BufferedReader
對象
String inputLine;
while ((inputLine = in.readLine()) != null)
//
從輸入流不斷的讀數據,直到讀完為止
System.out.println(inputLine); //
把讀入的數據打印到屏幕上
in.close(); //
關閉輸入流
}
}
8.2.6 通過URLConnetction連接WWW
通過
URL
的方法
openStream()
,我們只能從網絡上讀取數據,如果我們同時還想輸出數據,例如向服務器端的
CGI
程序發送一些數據,我們必須先與
URL
建立連接,然后才能對其進行讀寫,這時就要用到類
URLConnection
了。
CGI
是公共網關接口(
Common Gateway Interface
)的簡稱,它是用戶瀏覽器和服務器端的應用程序進行連接的接口,有關
CGI
程序設計,請讀者參考有關書籍。
類
URLConnection
也在包
java.net
中定義,它表示
Java
程序和
URL
在網絡上的通信連接。當與一個
URL
建立連接時,首先要在一個
URL
對象上通過方法
openConnection()
生成對應的
URLConnection
對象。例如下面的程序段首先生成一個指向地址
http://edu.chinaren.com/index.shtml
的對象,然后用
openConnection
()打開該
URL
對象上的一個連接,返回一個
URLConnection
對象。如果連接過程失敗,將產生
IOException.
Try{
URL netchinaren = new URL ("http://edu.chinaren.com/index.shtml");
URLConnectonn tc = netchinaren.openConnection();
}catch(MalformedURLException e){ //
創建
URL()
對象失敗
…
}catch (IOException e){ //openConnection()
失敗
…
}
類
URLConnection
提供了很多方法來設置或獲取連接參數,程序設計時最常使用的是
getInputStream()
和
getOurputStream(),
其定義為:
InputSteram getInputSteram();
OutputSteram getOutputStream();
通過返回的輸入
/
輸出流我們可以與遠程對象進行通信??聪旅娴睦樱?/span>
URL url =new URL ("http://www.javasoft.com/cgi-bin/backwards");
//
創建一
URL
對象
URLConnectin con=url.openConnection();
//
由
URL
對象獲取
URLConnection
對象
DataInputStream dis=new DataInputStream (con.getInputSteam());
//
由
URLConnection
獲取輸入流,并構造
DataInputStream
對象
PrintStream ps=new PrintSteam(con.getOutupSteam());
//
由
URLConnection
獲取輸出流,并構造
PrintStream
對象
String line=dis.readLine(); //
從服務器讀入一行
ps.println("client…"); //
向服務器寫出字符串
"client…"
其中
backwards
為服務器端的
CGI
程序。實際上,類
URL
的方法
openSteam
()是通過
URLConnection
來實現的。它等價于
openConnection().getInputStream();
基于
URL
的網絡編程在底層其實還是基于下面要講的
Socket
接口的。
WWW
,
FTP
等標準化的網絡服務都是基于
TCP
協議的,所以本質上講
URL
編程也是基于
TCP
的一種應用
.
8.3 基于Socket的低層次Java網絡編程
8.3.1 Socket通訊
網絡上的兩個程序通過一個雙向的通訊連接實現數據的交換,這個雙向鏈路的一端稱為一個
Socket
。
Socket
通常用來實現客戶方和服務方的連接。
Socket
是
TCP/IP
協議的一個十分流行的編程界面,一個
Socket
由一個
IP
地址和一個端口號唯一確定。
在傳統的
UNIX
環境下可以操作
TCP/IP
協議的接口不止
Socket
一個,
Socket
所支持的協議種類也不光
TCP/IP
一種,因此兩者之間是沒有必然聯系的。在
Java
環境下,
Socket
編程主要是指基于
TCP/IP
協議的網絡編程。
8.3.2 Socket通訊的一般過程
使用
Socket
進行
Client/Server
程序設計的一般連接過程是這樣的:
Server
端
Listen(
監聽
)
某個端口是否有連接請求,
Client
端向
Server
端發出
Connect(
連接
)
請求,
Server
端向
Client
端發回
Accept
(接受)消息。一個連接就建立起來了。
Server
端和
Client
端都可以通過
Send
,
Write
等方法與對方通信。
對于一個功能齊全的
Socket
,都要包含以下基本結構,其工作過程包含以下四個基本的步驟:
(
1
)
創建
Socket
;
?。?/span>
2
)
打開連接到
Socket
的輸入
/
出流;
(
3
)
按照一定的協議對
Socket
進行讀
/
寫操作;
?。?/span>
4
)
關閉
Socket.
8.3.3 創建Socket
java
在包
java.net
中提供了兩個類
Socket
和
ServerSocket
,分別用來表示雙向連接的客戶端和服務端
。這是兩個封裝得非常好的類,使用很方便。其構造方法如下:
Socket(InetAddress address, int port);
Socket(InetAddress address, int port, boolean stream);
Socket(String host, int prot);
Socket(String host, int prot, boolean stream);
Socket(SocketImpl impl)
Socket(String host, int port, InetAddress localAddr, int localPort)
Socket(InetAddress address, int port, InetAddress localAddr, int localPort)
ServerSocket(int port);
ServerSocket(int port, int backlog);
ServerSocket(int port, int backlog, InetAddress bindAddr)
其中
address
、
host
和
port
分別是雙向連接中另一方的
IP
地址、主機名和端口號,
stream
指明
socket
是流
socket
還是數據報
socket
,
localPort
表示本地主機的端口號,
localAddr
和
bindAddr
是本地機器的地址(
ServerSocket
的主機地址),
impl
是
socket
的父類,既可以用來創建
serverSocket
又可以用來創建
Socket
。
count
則表示服務端所能支持的最大連接數。例如:
Socket client = new Socket("127.0.01.", 80);
ServerSocket server = new ServerSocket(80);
注意,在選擇端口時,必須小心。每一個端口提供一種特定的服務,只有給出正確的端口,才能獲得相應的服務。
0~1023
的端口號為系統所保留,例如
http
服務的端口號為
80,telnet
服務的端口號為
21,ftp
服務的端口號為
23,
所以我們在選擇端口號時,最好選擇一個大于
1023
的數以防止發生沖突。
在創建
socket
時如果發生錯誤,將產生
IOException
,在程序中必須對之作出處理。所以在創建
Socket
或
ServerSocket
是必須捕獲或拋出例外。
8.3.8 簡單的Client/Server程序設計
下面我們給出一個用
Socket
實現的客戶和服務器交互的典型的
C/S
結構的演示程序,讀者通過仔細閱讀該程序,會對前面所討論的各個概念有更深刻的認識。程序的意義請參考注釋。
1. 客戶端程序
import java.io.*;
import java.net.*;
public class TalkClient {
public static void main(String args[]) {
try{
Socket socket=new Socket("127.0.0.1",4700);
//向本機的4700端口發出客戶請求
BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
//由系統標準輸入設備構造BufferedReader對象
PrintWriter os=new PrintWriter(socket.getOutputStream());
//由Socket對象得到輸出流,并構造PrintWriter對象
BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//由Socket對象得到輸入流,并構造相應的BufferedReader對象
String readline;
readline=sin.readLine();
//從系統標準輸入讀入一字符串
while(!readline.equals("bye")){
//若從標準輸入讀入的字符串為 "bye"則停止循環
os.println(readline);
//將從系統標準輸入讀入的字符串輸出到Server
os.flush();
//刷新輸出流,使Server馬上收到該字符串
System.out.println("Client:"+readline);
//在系統標準輸出上打印讀入的字符串
System.out.println("Server:"+is.readLine());
//從Server讀入一字符串,并打印到標準輸出上
readline=sin.readLine();
//從系統標準輸入讀入一字符串
}
//繼續循環
os.close();
//關閉Socket輸出流
is.close();
//關閉Socket輸入流
socket.close();
//關閉Socket
}catch(Exception e) {
System.out.println("Error"+e);
//出錯,則打印出錯信息
}
}
}
2. 服務器端程序
import java.io.*;
import java.net.*;
import java.applet.Applet;
public class TalkServer{
public static void main(String args[]) {
try{
ServerSocket server=null;
try{
server=new ServerSocket(4700);
//創建一個ServerSocket在端口4700監聽客戶請求
}catch(Exception e) {
System.out.println("can not listen to:"+e);
//出錯,打印出錯信息
}
Socket socket=null;
try{
socket=server.accept();
//使用accept()阻塞等待客戶請求,有客戶
//請求到來則產生一個Socket對象,并繼續執行
}catch(Exception e) {
System.out.println("Error."+e);
//出錯,打印出錯信息
}
String line;
BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//由Socket對象得到輸入流,并構造相應的BufferedReader對象
PrintWriter os=newPrintWriter(socket.getOutputStream());
//由Socket對象得到輸出流,并構造PrintWriter對象
BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
//由系統標準輸入設備構造BufferedReader對象
System.out.println("Client:"+is.readLine());
//在標準輸出上打印從客戶端讀入的字符串
line=sin.readLine();
//從標準輸入讀入一字符串
while(!line.equals("bye")){
//如果該字符串為 "bye",則停止循環
os.println(line);
//向客戶端輸出該字符串
os.flush();
//刷新輸出流,使Client馬上收到該字符串
System.out.println("Server:"+line);
//在系統標準輸出上打印讀入的字符串
System.out.println("Client:"+is.readLine());
//從Client讀入一字符串,并打印到標準輸出上
line=sin.readLine();
//從系統標準輸入讀入一字符串
}
//繼續循環
os.close();
//關閉Socket輸出流
is.close();
//關閉Socket輸入流
socket.close();
//關閉Socket
server.close();
//關閉ServerSocket
}catch(Exception e){
System.out.println("Error:"+e);
//出錯,打印出錯信息
}
}
}
8.3.9
支持多客戶的
client/server
程序設計
前面提供的
Client/Server
程序只能實現
Server
和一個客戶的對話。在實際應用中,往往是在服務器上運行一個永久的程序,它可以接收來自其他多個客戶端的請求,提供相應的服務。為了實現在服務器方給多個客戶提供服務的功能,需要對上面的程序進行改造,利用多線程實現多客戶機制。服務器總是在指定的端口上監聽是否有客戶請求,一旦監聽到客戶請求,服務器就會啟動一個專門的服務線程來響應該客戶的請求,而服務器本身在啟動完線程之后馬上又進入監聽狀態,等待下一個客戶的到來。
ServerSocket serverSocket=null;
boolean listening=true;
try{
serverSocket=new ServerSocket(4700);
//
創建一個
ServerSocket
在端口
4700
監聽客戶請求
}catch(IOException e) {
}
while(listening){ //
永遠循環監聽
new ServerThread(serverSocket.accept(),clientnum).start();
//
監聽到客戶請求,根據得到的
Socket
對象和
客戶計數創建服務線程,并啟動之
clientnum++; //
增加客戶計數
}
serverSocket.close(); //
關閉
ServerSocket
設計
ServerThread
類
public class ServerThread extends Thread{
Socket socket=null; //
保存與本線程相關的
Socket
對象
int clientnum; //
保存本進程的客戶計數
public ServerThread(Socket socket,int num) { //
構造函數
this.socket=socket; //
初始化
socket
變量
clientnum=num+1; //
初始化
clientnum
變量
}
public void run() { //
線程主體
try{//
在這里實現數據的接受和發送
}
8.3.10
據報
Datagram
通訊
前面在介紹
TCP/IP
協議的時候,我們已經提到,在
TCP/IP
協議的傳輸層除了
TCP
協議之外還有一個
UDP
協議,相比而言
UDP
的應用不如
TCP
廣泛,幾個標準的應用層協議
HTTP
,
FTP
,
SMTP…
使用的都是
TCP
協議。但是,隨著計算機網絡的發展,
UDP
協議正越來越來顯示出其威力,尤其是在需要很強的實時交互性的場合,如網絡游戲,視頻會議等,
UDP
更是顯示出極強的威力,下面我們就介紹一下
Java
環境下如何實現
UDP
網絡傳輸。
8.3.11
什么是
Datagram
所謂數據報(
Datagram
)就跟日常生活中的郵件系統一樣,是不能保證可靠的寄到的,而面向鏈接的
TCP
就好比電話,雙方能肯定對方接受到了信息。在本章前面,我們已經對
UDP
和
TCP
進行了比較,在這里再稍作小節:
TCP
,可靠,傳輸大小無限制,但是需要連接建立時間,差錯控制開銷大。
UDP
,不可靠,差錯控制開銷較小,傳輸大小限制在
64K
以下,不需要建立連接。
8.3.12 Datagram
通訊的表示方法:
DatagramSocket
;
DatagramPacket
包
java.net
中提供了兩個類
DatagramSocket
和
DatagramPacket
用來支持數據報通信,
DatagramSocket
用于在程序之間建立傳送數據報的通信連接,
DatagramPacket
則用來表示一個數據報。
先來看一下
DatagramSocket
的構造方法:
DatagramSocket
();
DatagramSocket
(
int prot
)
;
DatagramSocket(int port, InetAddress laddr)
其中,
port
指明
socket
所使用的端口號,如果未指明端口號,則把
socket
連接到本地主機上一個可用的端口。
laddr
指明一個可用的本地地址。給出端口號時要保證不發生端口沖突,否則會生成
SocketException
類例外。注意:上述的兩個構造方法都聲明拋棄非運行時例外
SocketException
,程序中必須進行處理,或者捕獲、或者聲明拋棄。
??
用數據報方式編寫
client/server
程序時,無論在客戶方還是服務方,首先都要建立一個
DatagramSocket
對象,用來接收或發送數據報,然后使用
DatagramPacket
類對象作為傳輸數據的載體。
下面看一下
DatagramPacket
的構造方法
:
DatagramPacket
(
byte buf[],int length
);
DatagramPacket(byte buf[], int length, InetAddress addr, int port);
DatagramPacket(byte[] buf, int offset, int length)
;
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
;
其中,
buf
中存放數據報數據,
length
為數據報中數據的長度,
addr
和
port
旨明目的地址,
offset
指明了數據報的位移量。
在接收數據前,應該采用上面的第一種方法生成一個
DatagramPacket
對象,給出接收數據的緩沖區及其長度。然后調用
DatagramSocket
的方法
receive()
等待數據報的到來,
receive()
將一直等待,直到收到一個數據報為止。
DatagramPacket packet=new DatagramPacket(buf, 256);
Socket.receive (packet);
發送數據前,也要先生成一個新的
DatagramPacket
對象,這時要使用上面的第二種構造方法,在給出存放發送數據的緩沖區的同時,還要給出完整的目的地址,包括
IP
地址和端口號。發送數據是通過
DatagramSocket
的方法
send()
實現的,
send()
根據數據報的目的地址來尋徑,以傳遞數據報。
DatagramPacket packet=new DatagramPacket(buf, length, address, port);
Socket.send(packet)
;
???
在構造數據報時,要給出
InetAddress
類參數。類
InetAddress
在包
java.net
中定義,用來表示一個
Internet
地址,我們可以通過它提供的類方法
getByName
()從一個表示主機名的字符串獲取該主機的
IP
地址,然后再獲取相應的地址信息。
8.3.14
用數據報進行廣播通訊
DatagramSocket
只允許數據報發送一個目的地址,
java.net
包中提供了一個類
MulticastSocket
,允許數據報以廣播方式發送到該端口的所有客戶。
MulticastSocket
用在客戶端,監聽服務器廣播來的數據。
1. 客戶方程序
:MulticastClient.java
import java.io.*;
import java.net.*;
import java.util.*;
public class MulticastClient {
public static void main(String args[]) throws IOException
{
MulticastSocket socket=new MulticastSocket(4446);
//創建4446端口的廣播套接字
InetAddress address=InetAddress.getByName("230.0.0.1");
//得到230.0.0.1的地址信息
socket.joinGroup(address);
//使用joinGroup()將廣播套接字綁定到地址上
DatagramPacket packet;
for(int i=0;i<5;i++) {
byte[] buf=new byte[256];
//創建緩沖區
packet=new DatagramPacket(buf,buf.length);
//創建接收數據報
socket.receive(packet);
//接收
String received=new String(packet.getData());
//由接收到的數據報得到字節數組,
//并由此構造一個String對象
System.out.println("Quote of theMoment:"+received);
//打印得到的字符串
}
//循環5次
socket.leaveGroup(address);
//把廣播套接字從地址上解除綁定
socket.close();
//關閉廣播套接字
}
}
2. 服務器方程序:MulticastServer.java
public class MulticastServer{
public static void main(String args[]) throws java.io.IOException
{
new MulticastServerThread().start();
//啟動一個服務器線程
}
}
3. 程序MulticastServerThread.java
import java.io.*;
import java.net.*;
import java.util.*;
public class MulticastServerThread extends QuoteServerThread
//從QuoteServerThread繼承得到新的服務器線程類MulticastServerThread
{
Private long FIVE_SECOND=5000;
//定義常量,5秒鐘
public MulticastServerThread(String name) throws IOException
{
super("MulticastServerThread");
//調用父類,也就是QuoteServerThread的構造函數
}
public void run() //重寫父類的線程主體
{
while(moreQuotes) {
//根據標志變量判斷是否繼續循環
try{
byte[] buf=new byte[256];
//創建緩沖區
String dString=null;
if(in==null) dString=new Date().toString();
//如果初始化的時候打開文件失敗了,
//則使用日期作為要傳送的字符串
else dString=getNextQuote();
//否則調用成員函數從文件中讀出字符串
buf=dString.getByte();
//把String轉換成字節數組,以便傳送send it
InetAddress group=InetAddress.getByName("230.0.0.1");
//得到230.0.0.1的地址信息
DatagramPacket packet=new DatagramPacket(buf,buf.length,group,4446);
//根據緩沖區,廣播地址,和端口號創建DatagramPacket對象
socket.send(packet);
//發送該Packet
try{
sleep((long)(Math.random()*FIVE_SECONDS));
//隨機等待一段時間,0~5秒之間
}catch(InterruptedException e) { }
//異常處理
}catch(IOException e){
//異常處理
e.printStackTrace( );
//打印錯誤棧
moreQuotes=false;
//置結束循環標志
}
}
socket.close( );
//關閉廣播套接口
}
}
【本講小結】
本講主要講解了
Java
環境下的網絡編程。因為
TCP/IP
協議是
Java
網絡編程的基礎知識,本講開篇重點介紹了
TCP/IP
協議中的一些概念,
TCP/IP
協議本身是一個十分龐大的系統,用幾個小節是不可能講清楚的。所以我們只是聯系實際,講解了一些最基本的概念,幫助學生理解后面的相關內容。重點有一下幾個概念:主機名,
IP
,端口,服務類型,
TCP
,
UDP
。
后續的內容分為兩大塊,一塊是以
URL
為主線,講解如何通過
URL
類和
URLConnection
類訪問
WWW
網絡資源,由于使用
URL
十分方便直觀,盡管功能不是很強,還是值得推薦的一種網絡編程方法,尤其是對于初學者特別容易接受。本質上講,
URL
網絡編程在傳輸層使用的還是
TCP
協議。
另一塊是以
Socket
接口和
C/S
網絡編程模型為主線,依次講解了如何用
Java
實現基于
TCP
的
C/S
結構,主要用到的類有
Socket
,
ServerSocket
。以及如何用
Java
實現基于
UDP
的
C/S
結構,還討論了一種特殊的傳輸方式,廣播方式,這種方式是
UDP
所特有的,主要用到的類有
DatagramSocket , DatagramPacket, MulticastSocket
。這一塊在
Java
網絡編程中相對而言是最難的(盡管
Java
在網絡編程這方面已經做的夠
"
傻瓜
"
了,但是網絡編程在其他環境下的卻是一件極為頭痛的事情,再
"
傻瓜
"
還是有一定的難度),也是功能最為強大的一部分
,
讀者應該好好研究,領悟其中的思想。
最后要強調的是要學好
Java
網絡編程,
Java
語言,最重要的還是在于多多練習!
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=102420