基於TCP/IP協議的Scoket JAVA程式設計
基於TCP/IP協議的Socket程式設計
1 TCP/IP協議
2 套接字(Socket)
2.1 Client/Server模式
2.2 套接字(Socket)概念
3 Socket類和ServerSocket類
3.1 Socket類
3.2 ServerSocket類
4 Socket程式設計應用舉例
4.1 Socket程式設計的基本步驟
4.2單客戶/伺服器Socket程式設計應用舉例
4.3多客戶/伺服器Socket程式設計應用舉例本章小結
1 TCP/IP協議
TCP/IP協議(傳輸控制協議/網際協議)是一種網路通訊協議,是一種面向連線的可靠的傳輸協議。它規範了網路上的所有通訊裝置,尤其是一個主機與另一個主機之間的資料傳輸格式以及傳送方式。TCP/IP是Internet的基礎協議。
TCP/IP協議的基本傳輸單位是資料包(datagram)。TCP協議負責把資料分成若干個datagram,並給每個datagram加上包頭;IP在每個包頭上再加上接收端主機地址,以確定資料傳輸的目的地。如果傳輸過程中出現數據丟失或資料失真等異常情況,TCP協議會自動要求資料重發,並重新分包。TCP保證資料傳輸的質量,IP協議保證資料的傳輸。
TCP/IP協議資料的傳輸是基於TCP/IP模型的4層結構:應用層、傳輸層、網路層和網路介面層。
在TCP/IP協議組中兩種主要協議
1、傳輸層協議
有兩個主要的傳輸層協議:傳輸控制協議(TCP)和使用者資料報協議(UDP)。
(1)傳輸控制協議(TCP)TCP傳輸資料建立在面向連線的基礎上,實現了一種“虛電路”的概念。雙方通訊之前,先建立連線,然後雙方即可在其上傳送資料流,傳送完畢後再關閉連線。這種資料交換方式的優點是效率高,缺點是建立連線和關閉連線需要額外的開銷。
(1)TCP協議主要提供下列服務:
- 可靠的資料傳輸
- 面向連線的虛電路
- 緩衝的傳輸
- 重新排序
- 多路複用技術
- 高效的、全雙工傳輸
- 流量控制
TCP協議提供的是一種可靠的資料流服務。得到的是一個順序的無差錯的資料流。
(2)使用者資料報協議(UDP)。UDP是比TCP簡單得多的協議,是對IP協議組的擴充。
由於大多數網路應用程式都在同一臺機器上執行,計算機上必須能夠確保目的地址機器上的軟體程式能從源地址機器處獲得資料包,以及源計算機能收到正確的回覆。這是通過使用UDP 的“埠號”完成的。源埠號標識了請求域名服務的本地計算機的應用程式,同時需要將所有由目的主機生成的響應包都指定到源主機的這個埠上。
(3)UDP與TCP比較
與TCP不同,UDP提供的是面向無連線、“不可靠”的資料報服務。它不提供對IP 協議的可靠機制、流控制以及錯誤恢復功能等。
由於UDP比較簡單,比TCP負載消耗少。主要用於不需要TCP排序和流量控制能力而是自己完成這些功能的應用程式。
2、應用層協議
在應用層中定義了許多高層協議:
(1)TELNET(遠端終端訪問)。TELNET連線是一個TCP連線。允許一臺計算機上的使用者登入到遠端計算機上並進行互動。支援終端到終端的連線及程序到程序分散式計算的通訊。
(2)FTP(檔案傳輸協議)FTP使得主機間可以共享檔案。FTP使用TCP生成一個虛擬連線用於控制資訊,然後再生成一個單獨的TCP連線用於資料傳輸。FTP主要提供檔案共享、支援間接使用遠端計算機、使使用者不因各類主機檔案儲存器系統的差異而受影響、可靠且有效的傳輸資料等功能。
(3)SMTP(簡單郵件傳輸協議)SMTP支援在因特網上傳遞電子郵件,用於可靠且有效的資料傳輸。它保證把各種型別的電子郵件通過這一協議從一臺郵件伺服器傳送到另一臺郵件伺服器上。
(4)DNS(域名服務)DNS提供域名到IP地址的轉換,允許對域名資源進行分散管理。
(5)HTTP(超文字傳輸協議)是Web瀏覽器和Web伺服器之間通訊的標準協議。它指明客戶端如何與伺服器建立連線,客戶端如何從伺服器請求資料,伺服器如何響應請求,最後連線如何關閉等。HTTP連線是一個TCP連線。
TCP/IP模型中還有其他一些協議,如地址解析協議(ARP)、因特網控制訊息協議(ICMP)等。
2 套接字(Socket)
套接字允許程式設計師把網路連線當成一個流(Stream),並向這個流讀寫位元組。Socket對程式設計師掩蓋了網路的低層細節,如糾錯、包大小、包重傳、網路地址等。本節將介紹Client/Server模式、套接字(Socket)概念。
2.1 Client/Server模式
計算機網路最重要的3個功能是資料通訊、資源共享和分佈處理。為了滿足這些功能需求,計算機網路產生了兩種重要的應用模式:客戶端/伺服器(Client/Server,C/S)模式和瀏覽器/伺服器(Brower/Server,B/S)模式。採用何種應用模式在程式設計實現時非常重要。下面將主要介紹C/S模式。
在C/S模式下,客戶向伺服器發出服務請求,伺服器接收到請求後,提供相應的服務。其工作方式可通過現實生活中一個例子來說明。在一個酒店中,顧客向服務員點菜,服務員把點選單通知廚師,廚師按點選單做好菜後讓服務員端給顧客,這就是一種C/S工作方式。如果把酒店看作一個系統,服務員就是客戶端,廚師就是伺服器,這種系統分工和協同工作的方式就是C/S的工作模式。
由此可見,工作在C/S模式下的系統被分成兩大部分:
(1)客戶端部分:為每個使用者所專有的,負責執行前臺功能。
(2)伺服器部分:由多個使用者共享的資訊與功能,招待後臺服務。
C/S模式建立的基礎C/S模式的建立基於以下兩點:
一是建立網路的起因是網路中軟硬體資源、運算能力和資訊不均等,需要共享,從而造就擁有眾多資源的主機提供服務,資源較少的客戶請求服務這一非對等作用。
二是網間程序通訊完全是非同步的,相互通訊的程序既不存在父子關係,又不共享記憶體緩衝區,因此需要一種機制為希望通訊的程序建立聯絡,為二者的資料交換提供同步,這就是基於C/S的TCP/IP。
C/S模式在操作過程中採取“請求/響應”的工作模式。當用戶需要訪問伺服器資源時由客戶端發出請求,伺服器接收到請求後做出響應,然後執行相應的服務,把執行結果返回到客戶端,再由客戶端作一定處理後返回給使用者。執行過程如下:
(1)伺服器偵聽相應埠的請求;
(2)客戶端發出一個請求;
(3)伺服器接收到此請求;
(4)伺服器處理這個請求,並把處理結果返回給客戶端。
從上面所描述的過程可知:客戶與伺服器程序的作用是非對稱的,因此編碼不同。服務程序一般是先於客戶請求而啟動的。只要系統執行,該服務程序一直存在,直到正常或強迫終止。
2.2 套接字(Socket)概念
資料在Internet中是以有限大小的分組的形式傳輸的。一個分組是一個數據報,包括首部和負載。首部包含目的的地址和埠、源地址和埠以及用於保證可靠傳輸的各種其他管理資訊。負載包含資料本身。但由於分組長度有限,通常必須將資料分解為多個分組,在目的地再重新組合。在傳輸過程中,有可能發生一個或多個分組丟失或被破壞的情況,此時就需要重傳分組。或者分組亂序到達,則需要重新排序。這些工作將是非常繁重的。
幸運的是,套接字(Socket)的出現使我們不必關心這些事情,我們只需要把網路看成一個流,就象對檔案操作一樣對這個流進行操作就行了。
套接字(Socket)是網路協議傳輸層提供的介面。Socket是兩個程式之間進行雙向資料傳輸的網路通訊端點,有一個地址和一個埠號來標識。每個服務程式在提供服務時都要在一個埠進行,而想使用該服務的客戶機也必須連線該埠。
目前共有兩種套接字
- 流套接字提供一個面向連線的、可靠的資料傳輸服務,保證資料無差錯、無重複、按順序傳送。具有流量控制功能。資料被看作位元組流,無長度限制。TCP即是一種基於流套接字的通訊協議。
- 資料報套接字提供一個面向無連線的資料傳輸服務,不保證資料傳輸是可靠的、有序的、無重複的。UDP即是一種基於資料報套接字的通訊協議。
本章主要介紹基於TCP/IP協議的C/S模式下的Socket程式設計。
在該種模式下,Socket可以看成是在兩個程式進行通訊連線中的一個端點,一個程式將一段資訊寫入Socket中,該Socket將這段資訊傳送到另外一個Socket中,使這段資訊能傳送到其他程式。每一個基於TCP/IP的程式都賦予了一個埠號(0~65535),通過不同的埠號,區別伺服器上執行的每一個應用程式和所提供的服務。值得注意的是,習慣上將低於1024的埠號保留給系統服務使用。
在兩個網路應用程式傳送和接收資訊時都需建立一個可靠的連線,流套接字依靠TCP來保證資訊正確到達目的地。實際上,IP分組有可能在網路中丟失或者在傳送過程中發生錯誤。當任何一種情況發生時,作為接收方的TCP將請求傳送方TCP重發這個IP分組。因此,兩個流套接字之間建立的連線是可靠的連線。
Socket可進行的基本操作
(1)連線遠端主機
(2)傳送資料
(3)接收資料
(4)關閉連線
(5)繫結埠
(6)偵聽入站資料
(7)在所繫結埠上接收遠端主要的連線
利用Socket程式設計的一般步驟:
(1)分別為伺服器和客戶端建立Socket物件,建立Socket連線。
(2)開啟連線到Socket的輸入輸出流。Socket物件包含兩個流:一個是輸入流,表示流入的資料流,其作用是接收資料;一個是輸出流,表示流出的資料流,其作用是向外傳送資料,其流操作與I/O流相同。
(3)按照一定的協議對Socket進行讀/寫操作,在本章裡是基於TCP/IP協議;
(4)讀/寫操作結束後,關閉Socket連線。
3 Socket類和ServerSocket類
在Java語言中,伺服器端Socket使用ServerSocket類,客戶端Socket使用Socket類,由此來區別伺服器端和客戶端。
3.1 Socket類
java.net .Socket類是Java用來實現客戶端TCP操作的基礎類,在Java程式設計中一切與TCP有關的操作包括連線的建立、傳輸、連線關閉及Socket選項的設定都由Socket類負責,這個類本身使用直接程式碼通過主機作業系統的本地TCP棧進行通訊。Socket類的輸入輸出都是通過流來實現的。 Socket類常用方法如下:
1.Socket類的建構函式
(1)public Socket(String host,int port) throws UnknownHostException, IOException功能:在客戶端以指定的伺服器host和埠號port建立一個Socket物件,並向伺服器發出連線請求。
引數:
host:伺服器主機名。
port:埠號。
若域名伺服器無法解析該伺服器名或域名伺服器沒有執行,此時host無法可知,則丟擲UnknownHostException異常;若生成Socket時發生I/O錯誤則丟擲IOException異常。
(2)public Socket(InetAddress address,int port) throws IOException功能:在客戶端以指定的伺服器地址address和埠號port建立一個Socket物件,並向伺服器發出連線請求。
引數:
address:伺服器IP地址。
port:埠號。
若生成Socket時發生I/O錯誤則丟擲IOException異常。
(3)public Socket(String host,int port,boolean stream) throws IOException功能:在客戶端以指定的伺服器host和埠號port建立Socket物件,並向伺服器發出連線請求。如果stream值為true,則建立流Socket物件,否則建立資料報Socket 物件。
引數:
host:伺服器名。
port:埠號。
stream:建立流Socket物件或建立資料報Socket物件的標誌。
若生成Socket時發生I/O錯誤則丟擲IOException異常。
(4)public Socket(InetAddress address,int port,boolean stream) throws IOException功能:在客戶端以指定的伺服器IP地址address和埠號port建立Socket物件,並向伺服器發出連線請求。如果stream值為true,則建立流Socket物件,否則建立資料報Socket 物件。
引數:
address:伺服器IP地址。
port:埠號。
stream:建立流Socket物件或建立資料報Socket物件的標誌。
若生成Socket時發生I/O錯誤則丟擲IOException異常。
(5)public Socket(InetAddress address,int port,InetAddress localAddr,int localPort) throws IOException功能:生成一個Socket並且連線到由address指定的伺服器的埠port上。該Socket將捆綁到由localAddr指定的本地主機的localPort埠上。
引數:
address:伺服器IP地址。
port:埠號。
localAddr:本地主機的IP地址。
localPort:本地主機上的埠號。
若生成Socket時發生I/O錯誤則丟擲IOException異常。
(6)public Socket(String host,int port, InetAddress localAddr,int localPort) throws IOException功能:生成一個Socket並且連線到由host指定的伺服器的埠port上。該Socket將捆綁到由localAddr指定的本地主機的localPort埠上。
引數:
host:伺服器名。
port:埠號。
localAddr:本地主機的IP地址。
localPort:本地主機上的埠號。
若生成Socket時發生I/O錯誤則丟擲IOException異常。
(7)protected Socket(SocketImpl impl) throws SocketException功能:根據使用者指定的SocketImpl生成一個無連線的socket。
引數:
impl:子類希望用在Socket上的SocketImpl 例項。
建立無連線失敗時丟擲SocketException異常。
客戶端流Socket的建立可通過使用Socket類的建構函式完成。建構函式不僅可以建立Socket物件,並且會嘗試連線伺服器端的Socket。可通過這個方法測試某個埠的連線是否允許。
2.與Socket資料讀寫有關的常用方法
(1)public InetAddress getInetAddress()
功能:獲取建立socket連線時指定伺服器的IP地址。
(2)public InetAddress getLocalAddress()
功能:獲取建立socket連線時客戶端主機的IP地址。
(3)public int getPort()
功能:獲取建立Socket連線時指定的伺服器的埠號。
(4)public int getLocalPort()
功能:獲取建立Socket連線時客戶端的埠號。
(5)public InputStream getInputStream() throws IOException
功能:為當前的socket物件建立輸入流。
(6)public OutputStream getOutputStream() throws IOException
功能:為當前的socket物件建立輸出流。
(7)public String toString()
功能:轉換該Socket成一個String.字串表示。
3.關閉Socket連線的方法
public synchronized void close() throws IOException
功能:關閉建立的Socket連線。當通訊結束時,應呼叫該方法關閉Socket連線。
若在關閉Socket連線時發生I/O錯誤則丟擲IOException異常。
【例 1】
//建立socket連線後獲取socket連線的相關資訊
import java.net.*;
import java.io.*;
public class SocketInfo {
public static void main(String args[]){
try{
Socket sktobj = new Socket("www.sina.com.cn",8080);
System.out.println("1:connect to "+sktobj.getInetAddress()+"on port "+sktobj.getPort());
System.out.println("2:from port "+sktobj.getLocalPort()+" of"+sktobj.getLocalAddress());
}
catch(UnknownHostException e){System.out.println(e);}
catch(IOException e){System.out.println(e);}
}
}
圖 4
【例 2】
//客戶端向伺服器傳送一個字串,伺服器接收並返回
import java.net.*;
import java.io.*;
public class SocketAppClient{
public static void main(String args[]){
int port=134;
try{
Socket sc = new Socket("127.0.0.1",port);//建立本地socket連線
OutputStream out = sc.getOutputStream();
DataOutputStream dout = new DataOutputStream(out);
//獲取輸出流,並建立相應的資料輸出流
dout.writeUTF("Tom"); //將tom寫入輸出流
InputStream in = sc.getInputStream();
DataInputStream din = new DataInputStream(in);
//獲取輸入流,並建立相應的資料輸入流
String str = din.readUTF();
System.out.println(str);
in.close();
out.close();
sc.close();
}
catch(UnknownHostException e){System.out.println(e);}
catch(IOException e){System.out.println(e);}
}
}
執行結果:單方通訊,缺伺服器
圖 5
3.2 ServerSocket類
ServerSocket類用在伺服器端,偵聽和響應客戶端的連線請求,並接收客戶端傳送的資料。ServerSocket類的主要任務是在伺服器端耐心地等候客戶端的連線請求,一旦客戶端應用程式申請建立一個Socket連線,ServerSocket類就會通過accept()方法返回一個對應的伺服器端Socket物件,以便進行直接通訊。從兩臺計算機連線成功時起,伺服器端與客戶端就得到了一個真正的“Socket-Socket”連線。
1.ServerSocket類建構函式
(1)public ServerSocket(int port) throws IOException
功能:建立一個指定埠號的伺服器端的socket。請求連線佇列的最大佇列長度為50,若連線請求到達時佇列已滿,則拒絕連線。埠號為0指在任何空閒埠上建立socket。
引數: port:埠號。
若無法建立Socket並綁定於所請求的埠號則丟擲IOException異常。
(2)public ServerSocket(int port,int backlog) throws IOException
功能:建立一個指定埠號的伺服器端的socket。請求連線佇列的最大佇列長度設定為backlog,若連線請求到達時佇列已滿,則拒絕連線。埠號為0指在任何空閒埠上建立socket。
引數:
port:埠號。
backlog:請求連線佇列的最大長度。
若無法建立Socket並綁定於所請求的埠號則丟擲IOException異常。
(3)public ServerSocket(int port,int backlog,InetAddress bindAddr) throws IOException
功能:建立一個指定埠號的伺服器端的socket。請求連線佇列的最大佇列長度設定為backlog,若連線請求到達時佇列已滿,則拒絕連線。埠號為0指在任何空閒埠上建立socket。與其它建構函式不同的是,該建構函式要指定要繫結到的本地IP地址。主要用於在多IP地址系統上執行的伺服器。此時,它允許先把所偵聽的地址,伺服器Socket只在指定的地址偵聽入站連線,不會偵聽通過主機其他地址進入的連線。其他建構函式預設繫結本地主機的所有IP地址。當bindAddr為null時,預設地接受對任何所有本地IP地址的連線。
引數:
port:埠號。
backlog:請求連線佇列的最大長度。
bindAddr:將捆綁到的本地IP地址.
若無法建立Socket並綁定於所請求的埠號則丟擲IOException異常。
【例 3】
//採用ServerSocket類查詢埠號為130~140的埠號中哪個埠可建立連線。
import java.net.*;
import java.io.*;
public class PortScan2{
public static void main(String args[]){
String host="localhost";
for(int i=130;i<140;i++)
try{ServerSocket a=new ServerSocket(i);
//在埠號i建立連線
System.out.println("there is a server on port:"+i);
//若可以建立連線,則輸出提示資訊
}catch(IOException e){System.out.println(e);
}//若埠已被佔用,則丟擲異常
}
}
執行結果:斷口號為135的埠已被佔用,當試圖在埠135建立連線時丟擲異常,即埠已被繫結.
圖 6
2.ServerSocket類的常用方法
(1)public InetAddress getInetAddress()功能:獲取伺服器端Socket的IP地址。
(2)public int getLocalPort()功能:獲取伺服器正偵聽的埠號。
(3)public Socket accept() throws IOException功能:在伺服器端指定埠偵聽客戶端發出的連線請求並與之連線。該方法一直阻塞直到連線成功。該方法返回一個新的Socket物件,通過該物件與客戶端進行通訊。若等待連線時發生I/O錯誤則丟擲IOException異常。
(4)public String toString()功能:返回該socket的字串表示
3.關閉Socket連線的方法
public void close() throws IOException
功能:關閉該socket連線。當伺服器需要關閉,不處理任何其他入站連線時,呼叫該方法。
若關閉socket時發生I/O錯誤則丟擲IOException異常。
【例 4】
//與8.2對應的伺服器端程式
import java.net.*;
import java.io.*;
public class SocketAppServer{
public static void main(String args[]){
ServerSocket ss = null;
int port = 134;
String hello = "From Server:Hello World!";
try{
ss = new ServerSocket(port);
//建立伺服器Socket連線,其偵聽埠為port,port與客戶端相同
}
catch(IOException e){
System.out.println(e);//若埠已被佔用,則丟擲異常
System.exit(1);
}
while(true){
try{
System.out.println("正在等待連線埠port=" + port + "...");
Socket cs = ss.accept();
InputStream in = cs.getInputStream();
DataInputStream din = new DataInputStream(in);
//獲取輸入流,並建立相應的資料輸入流
String name = din.readUTF();
OutputStream out = cs.getOutputStream();
DataOutputStream dout = new DataOutputStream(out);
//獲取輸出流,並建立相應的資料輸出流
dout.writeUTF(hello+"Your name:" + name);//將字串寫入輸出流
System.out.println("已成功連線埠port=" + port);
System.out.println("=========================================");
in.close();
out.close();
cs.close();
}
catch(IOException e){
System.out.println(e);//若埠已被佔用,則丟擲異常
}
}
}
}
執行結果:
(1)首先執行例4的伺服器端程式
圖 7
(2)執行例2的客戶端程式
4 Socket程式設計應用舉例
4.1 Socket程式設計的基本步驟
1.伺服器端應用程式編寫步驟
(1)建立一個等待連線的ServerSocket物件,如Sersocket;
(2)呼叫Sersocket物件的accept()方法偵聽接收客戶端的連線請求。當偵聽到一個客戶的連線請求時,連線成功,並返回一個用於通訊的Socket物件;
(3)建立與Socket物件繫結的輸入輸出流,並建立相應的資料輸入輸出流;
(4)通過資料輸入輸出流與客戶端進行資料讀寫,完成雙向通訊;
(5)當客戶端斷開連線時,關閉各個流物件,結束通訊。(2)~(5)可迴圈執行。
2.客戶端應用程式編寫步驟
(1)建立指定伺服器上指定埠號的Socket物件;
(2)建立與Socket物件繫結的輸入輸出流,並建立相應的資料輸入輸出流;
(3)通過資料輸入輸出流與伺服器端進行資料讀寫,完成雙向通訊;
(4)通過呼叫close()方法關閉與伺服器端的連線,並關閉各個流物件,結束通訊。
4.2單客戶/伺服器Socket程式設計應用舉例
【例 5】
編寫一個基於TCP協議的Socket網路點對點聊天程式,可實現客戶端和伺服器端資訊的互發。
1.伺服器端程式talkserver.java
//點對點聊天程式,伺服器端
import java.net.*;
import java.io.*;
public class talkserver{
public static void main(String args[]){
ServerSocket server = null;
Socket socket;
String s;//中間字串
int port = 2000;
String hello = "From Server:Hello World!";
try{
server = new ServerSocket(port);
//建立伺服器Socket連線,其偵聽埠為port,port與客戶端相同
System.out.println("正在等待連線埠port=" + port + "...");
socket = server.accept();
System.out.println("已成功連線埠port=" + port);
System.out.println("=========================================");
InputStream in = socket.getInputStream();
DataInputStream din = new DataInputStream(in);
//獲取輸入流,並建立相應的資料輸入流
OutputStream out = socket.getOutputStream();
DataOutputStream dout = new DataOutputStream(out);
//獲取輸出流,並建立相應的資料輸出流
BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("請等待客戶傳送資訊...");
while(true){
System.out.println("");
s = din.readUTF(); //讀入從client傳來的字串
System.out.println("從客戶端接收的資訊為:" + s);//顯示字串
if(s.trim().equals("BYE")) {System.out.print("通話結束" );break;}
System.out.println("");
System.out.print("請輸入要傳送的資訊:" );//顯示字串
s = sin.readLine(); //讀入從client傳來的字串
dout.writeUTF(s);
if(s.trim().equals("BYE")) {System.out.print("通話結束" );break;}
}
din.close();
dout.close();
in.close();
out.close();
socket.close();
}
catch(IOException e){
System.out.println("Error" + e);//若埠已被佔用,則丟擲異常
System.exit(1);
}
}
}
程式分析:
程式首先在埠2000上建立一個等待連線請求的ServerSocket物件sever:
server=new ServerSocket(2000);
接著呼叫Server物件的accept()方法等待某客戶程式發出的連線請求。該方法一直阻塞直到有客戶連線到該埠。一旦有客戶傳送正確請求,則連線成功,accept()方法返回一個Socket物件,於是得到一個新的用於通訊的Socket物件,通訊鏈路建立成功.然後利用Socket類提供的getInputStream()和getOutputStream()方法建立與Socket物件繫結的輸入/輸出流.此後即可與客戶進行通訊,直到客戶端斷開連線即關閉各個流結束通訊.
2.客戶端程式talkclient.java
import java.net.*;
import java.io.*;
public class talkclient{
public static void main(String args[]){
Socket socket;
String s;
int port = 2000;
try{
//向本地伺服器申請連線
//注意埠號要和伺服器的一致
socket = new Socket("localhost",port);//localhost=127.0.0.1
System.out.println("連線成功");
System.out.println("=========================================");
System.out.println("");
//獲得對應Socket的輸入/輸出流
InputStream in = socket.getInputStream();
DataInputStream din = new DataInputStream(in);
//獲取輸入流,並建立相應的資料輸入流
OutputStream out = socket.getOutputStream();
DataOutputStream dout = new DataOutputStream(out);
//獲取輸出流,並建立相應的資料輸出流
BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
while(true){
System.out.print("請輸入要傳送的資訊:" );//顯示字串
s = sin.readLine(); //讀入從client傳來的字串
dout.writeUTF(s);
if(s.trim().equals("BYE")) {System.out.print("通話結束" );break;}
System.out.println("");
s = din.readUTF(); //讀入從client傳來的字串
System.out.println("從伺服器接收的資訊為:" + s);//顯示字串
if(s.trim().equals("BYE")) {System.out.print("通話結束" );break;}
System.out.println("");
}
din.close();
dout.close();
in.close();
out.close();
socket.close();
}
catch(IOException e){
System.out.println("Error" + e);//若埠已被佔用,則丟擲異常
System.exit(1);
}
}
}
執行結果:
(1) 執行伺服器端程式talkserver.java
(2)執行客戶端程式talkclient.java
(3)客戶端向服務端傳送資訊
【例 6】
多客戶/伺服器程式。
1.伺服器端程式
(1)ServerSocketThread.java:執行緒類的子類,為客戶提供服務的所有操作都封裝在該類中,該類的建構函式ServerSocketThread(Socket s)接收一個Socket物件,用來與客戶進行資料通訊。
import java.net.*;
import java.io.*;
public class ServerSocketThread extends Thread{
private Socket socket;
private DataInputStream din;
private DataOutputStream dout;
public ServerSocketThread(Socket s) throws IOException{
socket = s;
din = new DataInputStream(socket.getInputStream());
dout = new DataOutputStream(socket.getOutputStream());
start();
}
public void run(){
String str;
try{
System.out.println("連線成功");
System.out.println("=========================================");
System.out.println("請等待客戶傳送資訊...");
System.out.println("");
while(true){
BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("");
str = din.readUTF(); //讀入從client傳來的字串
System.out.println("從客戶端接收的資訊為:" + str);//顯示字串
if(str.trim().equals("BYE")) {System.out.print("通話結束" );break;}
System.out.println("");
System.out.print("請輸入要傳送的資訊:" );//顯示字串
str = sin.readLine(); //讀入從鍵盤傳來的字串
dout.writeUTF(str);
dout.flush(); // http://blog.sina.com.cn/s/blog_82f2fc280100z3rr.html
if(str.trim().equals("BYE")) {System.out.print("通話結束" );break;}
}
din.close();
dout.close();
socket.close();
}
catch(IOException e){
System.out.println("Error" + e);//若埠已被佔用,則丟擲異常
System.exit(1);
}
}
}
(2)MultitalkServer.java:是一個應用程式,通過一個無限迴圈,等待並偵聽多個客戶的連線請求,每個客戶的連線都由伺服器端的一個單獨執行緒來處理,實現了多使用者/伺服器之間的通訊。
import java.net.*;
import java.io.*;
public class MultitalkServer{
public static void main(String args[]){
int port = 2000;
try{
System.out.println("正在等待連線...");
ServerSocket server = new ServerSocket(port);
Socket socket = null;
while(true){
socket = server.accept();
new ServerSocketThread(socket);//偵聽連線請求,等待連線
}
}
catch(IOException e){
System.out.println("Error" + e);//若埠已被佔用,則丟擲異常
System.exit(1);
}
}
}
2.客戶端程式
(1)ClientSocketThread.java:客戶端執行緒子類,實現和伺服器的資料通訊
import java.net.*;
import java.io.*;
public class ClientSocketThread extends Thread{
private Socket socket;
private DataInputStream din;
private DataOutputStream dout;
private int port;
public ClientSocketThread(InetAddress addr,int port,String clientname) throws IOException{
super(clientname);
socket = new Socket(addr,port);
din = new DataInputStream(socket.getInputStream());
dout = new DataOutputStream(socket.getOutputStream());
start();
}
public void run(){
String str;
try{
System.out.println(getName());
BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("連線成功");
System.out.println("=========================================");
System.out.println("");
while(true){
System.out.println("");
System.out.print("請輸入要傳送的資訊:" );//顯示字串
str = sin.readLine(); //讀入從client傳來的字串
dout.writeUTF(str);
dout.flush();
if(str.trim().equals("BYE")) {System.out.print("通話結束" );break;}
System.out.println("");
str = din.readUTF(); //讀入從client傳來的字串
System.out.println("從客戶端接收的資訊為:" + str);//顯示字串
if(str.trim().equals("BYE")) {System.out.print("通話結束" );break;}
}
din.close();
dout.close();
socket.close();
}
catch(IOException e){
System.out.println("Error" + e);//若埠已被佔用,則丟擲異常
System.exit(1);
}
}
}
(2)TalkClient1.java和TalkClient2.java:建立和伺服器通訊的客戶1和客戶2
//------------------------------TalkClient1.java--------------------------------------------
import java.net.*;
import java.io.*;
public class talkClient1{
public static void main(String args[]){
int port = 2000;
try{
new ClientSocketThread(InetAddress.getLocalHost(),port,"客戶端1");
}
catch(IOException e){
System.out.println("Error" + e);//若埠已被佔用,則丟擲異常
System.exit(1);
}
}
}
//-------------------------TalkClient2.java--------------------------------------
import java.net.*;
import java.io.*;
public class talkClient2{
public static void main(String args[]){
int port = 2000;
try{
new ClientSocketThread(InetAddress.getLocalHost(),port,"客戶端2");
}
catch(IOException e){
System.out.println("Error" + e);//若埠已被佔用,則丟擲異常
System.exit(1);
}
}
}
執行結果:
TCP/IP協議
Client/Server模式
套接字(Socket)概念
Socket類
ServerSocket類
基於TCP協議的Socket程式設計的基本步驟
單客戶/伺服器Socket程式設計應用
多客戶/伺服器Socket程式設計應用
原始檔:
TCP協議的基本流程圖,以及三次握手機制
常見的使用tcp協議的有ftp,smtp,telnet,snmp等。
MSL,最長分節生命週期,maximum segment lifetime,每個TCP實現都必須有個MSL值,它代表IP資料包能
在網際網路上生存的最長時間。
TTL,Time to life是IP協議包中的一個值,它告訴網路,資料包(例如ICMP包)在網路中的時間是否太長而應
被丟棄。有很多原因使包在一定時間內不能被傳遞到目的地。
MTU ,最大傳輸單元,maximum transport unit,由鏈路層規定。一個IP資料包傳出時,如果大於MTU,則會執行分片,各分片在到達目的地前是不會進行重組的。另外,IPV4主機和路由都可能對資料包執行分片,但是IPV6只有主機會在資料包產生時執行分片,IPV6路由器是不會對過路的資料包進行分片的。
MSS,最大分節大小,maximux segment size, 能接受的每個tcp分節中的最大資料量。
TCP,傳輸控制協議,transport control protocol
UDP,使用者資料報協議,userdata protocol
ICMP ,網際控制訊息協議,internet control message protocol
ARP, 地址解析協議, address resolv protocol