1.IP地址與埠號
網路中的計算機若需要實現相互通信,必須為每台計算機指定標識號,通過標識號來指定接收數據和識別發送數據的計算機。TCP/IP協議中的「標識」即為IP地址。
一台計算機可同時運行多個網路程序,使用IP地址能夠將數據發送到計算機,卻不能保證將數據提交至哪個網路程序。因此每個被發送的網路數據包的頭部都設有「埠」部分,該部分為整數,用於表示將數據幀交給哪個應用程序進行處理。同時還必須為網路程序指定埠號,使不同的應用程序接收不同埠上的數據。
同一台計算機不能存在多個使用同一埠的程序。埠數的范圍在0-65535之間,其中在0-1023之間的埠號用於知名的網路服務和應用,1024以上的埠號用於普通應用程序,這樣做可以避免埠號代表的網路程序串用。
2.TCP與UDP
TCP為傳輸控制協議,UDP為用戶數據報協議。TCP是面向連接的通信協議,它提供兩台計算機之間可靠無差錯的數據傳輸。應用程序使用TCP進行通信時,數據源與目標之間將建立虛擬的連接,連接一旦建立,兩台計算機之間就可以將數據作為雙向位元組流進行交換。
UDP是無連接的通信協議,它不保證可靠數據的傳輸,但能夠實現向若干個目標發送數據的功能。
3.Socket簡介
Socket(套接字)是網路驅動層為應用程序提供的介面和機制,其作用可以看作是為應用程序創建的港口碼頭。
4.TCP網路編程概述
TCP協議具體操作步驟如下:
(1)伺服器程序創建ServerSocket對象,調用accept()方法等待客戶端連接。
(2)客戶端程序創建Socket對象與客戶端建立專線連接。
(3)伺服器接收客戶的連接請求,並創建新的Socket對象與客戶端建立專線連接。
(4)實現(2)、(3)步驟中建立連接的兩個Socket在同一線程上對話。
(5)伺服器重新等待新的連接請求。
5.ServerSocket類
TCP網路伺服器程序的編寫,需要使用ServerSocket類創建伺服器。
ServerSocket類的主要方法如下:
方法 類型 描述
public ServerSocket(int port) 構造方法 創建ServerSocket實例
public Socket accept() 方法 等待客戶端連接
public InetAddress getInetAddress() 方法 返回伺服器的IP地址
public boolean isClosed() 方法 返回ServerSocket的關閉狀態
public void close() 方法 關閉ServerSocket
伺服器端每次運行時均需調用accept()方法等待客戶端連接,該方法執行後服務端將進入阻塞狀態,直到客戶端再次連接。accept()方法的返回類型為Socket。
6.Socket類
客戶端必須創建Socket對象來建立與伺服器的連接,每個Socket對象代表一個客戶端。
Socket類的常用方法如下:
方法 類型 描述
public Socket(String host,int port) 構造方法 創建Socket對象,同時指定要連接伺服器的主機名和商品號
public InputStream getInputStream() 方法 返回套接字的輸入流
public OutputStream getOutputStream() 方法 返回套接字的輸出流
public boolean isClosed() 方法 返回套接字的關閉狀態
public void close() 方法 關閉此Socket
注意:TCP網路編程中的信息使用輸入輸出流的形式傳遞。
7.TCP伺服器程序
編寫TCP伺服器程序,代碼如下:
package com;
import java.net.*;
import java.io.*;
public class TcpServer{
public static void main(String []a){
ServerSocket server=null;
Socket socket=null;
BufferedReader in=null;
PrintWriter out=null;
try{
//伺服器在9000埠上監聽
server=new ServerSocket(9000);
//接收客戶端連接
socket=server.accept();
//得到客戶端輸入信息
in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//向客戶端輸出信息,true是自動刷新緩沖區
out=new PrintWriter(socket.getOutputStream(),true);
out.println("已建立與伺服器的連接");
String info=in.readLine();
System.out.println("客戶端的輸入是:"+info);
}catch(Exception e){
e.printStackTrace();
}
finally{
try{
in.close();
out.close();
socket.close();
server.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
為驗證伺服器端程序能否正常工作,程序還需提供客戶端程序與伺服器進行通信。Windows系統中的telnet程序是一個系統自帶的TCP客戶端,可以使用telnet來進行與伺服器端的通信測試。運行telnet時指定連接伺服器的IP地址和埠號,連接一旦建立,telnet程序窗口就可以將輸入內容發送至伺服器,同時,可以顯示從伺服器接收到的數據。測試步驟如下:
(1) 運行伺服器端程序
(2) 在DOS窗口中運行telnet 127.0.0.1 9000,由於伺服器端程序和客戶端程序在同一台機器上,所以可以使用127.0.0.1代表本機。
註:調用一次accept()方法只能接受一個連接,接受多個連接需要將該方法放在循環語句中,同時每個連接的數據的數據輸入輸出也應放在一個循環語句中,才能實現伺服器端與客戶端的持續交換。
class Service implements Runnable{
Socket socket=null;
BufferedReader in=null;
PrintWriter out=null;
public Service(Socket socket){
this.socket=socket;
}
public void run(){
//得到客戶端輸入信息
in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//向客戶端輸出信息,true是自動刷新緩沖區
out=new PrintWriter(socket.getOutputStream(),true);
//循環讀取客戶端數據並向客戶端寫入數據
while(true){
out.println("已建立與伺服器的連接");
System.out.println("客戶端說:"+in.readLine());
}
}
catch(Exception e){
e.printStackTrace();
}
finally{
try{
in.close();
out.close();
socket.close();
server.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
public class TcpServer{
ServerSocket server=null;
Socket socket=null;
try{
//伺服器在9000埠上監聽
server=new ServerSocket(9000);
//接收多個客戶端連接
while(true){
socket=server.accept();
new Thread(new Service(socket)).start();
}catch(Exception e){
e.printStackTrace();
}
}
}
8.TCP客戶端程序
package com;
import java.net.*;
import java.io.*;
public class TcpClient{
public static void main(String []a){
ServerSocket server=null;
Socket socket=null;
BufferedReader in=null;
BufferedReader input=null;
PrintWriter out=null;
try{
socket=new Socket("127.0.0.1",9000);
while(true){
input=new BufferedReader(new InputStreamReader(System.in);
in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
//向伺服器端輸出信息,true是自動刷新緩沖區
out=new PrintWriter(socket.getOutputStream(),true);
out.println("客戶端說:"+input.readLine);
String info=in.readLine();
System.out.println("伺服器說:"+info);
}catch(Exception e){
e.printStackTrace();
}
}
}
9.UDP網路編程
(1)DatagramSocket類主要用於實現信息的發送和接收。
DatagramSocket類的主要方法:
方法 類型 描述
public DatagramSocket() 構造方法 構造DatagramSocket對象不指定監聽埠
public DatagramSocket(int port) 構造方法 構造DatagramSocket對象指定監聽埠
public void send(DatagramPacket p) 方法 發送數據報
public void receive(DatagramPacket p) 方法 接收數據報
(2)DatagramPacket類
DatagramPacket類用於包裝一條要發送或接收的信息,發送數據和接收數據都需要構建DatagramPacket對象。
DatagramPacket類的主要方法:
方法 類型 描述
public DatagramPacket(byte[] buf,in length) 構造方法 構造DatagramPacket對象時指定內存空間和大小
public DatagramPacket(byte[] buf,in length,InetAddress address,int port) 同上
public byte[] getData() 方法 返回接收數據
public int getLength() 方法 返回發送或接收數據的長度
public InetAddress getAddress() 方法 返回機器的地址
(3)InetAddress類
InetAddress類用於表示計算機地址,主要方法如下:
方法 類型 描述
public static InetAddress getByName(String host) 方法 通過主機名或IP地址獲得一個InetAddress對象
public String getHostName() 方法 獲得IP地址對應的主機名
public String getHostAddress() 方法 返回IP地址字元串
10. UDP程序設計
編寫UDP網路程序需要分別編寫發送程序和接收程序
(1)發送程序
package com;
import java.net.*;
public class UdpSend{
public static void main(String [] a){
DatagramSocket ds=null;
DatagramPacket dp=null;
byte[] buf=new byte[1024];
try{
//DatagramSocket類用於完成消息的發送
ds=new DatagramSocket();
String info="hello world";
dp=new DatagramPacket(info.getBytes(),info.length,InetAddress.getByName("localhost"),3000);
//發送數據包
ds.send(dp);
}catch(Exception e){
e.printStackTrace();
}
finally
{
ds.close(); //消息發送完畢,關閉對象
}
}
}
(2)接收程序
package com;
import java.net.*;
public class UdpRecv{
public static void main(String [] a){
DatagramSocket ds=null;
DatagramPacket dp=null;
byte[] buf=new byte[1024];
try{
//DatagramSocket類用於完成消息的發送
ds=new DatagramSocket();
dp=new DatagramPacket(buf,1024);
//接收發送方發送的數據
ds.receive(dp);
String str=new String(dp.getData(),0,dp.getLength());
str=str+" from "+dp.getAddress.getHostAddress();
System.out.println(str);
}catch(Exception e){
e.printStackTrace();
}
finally
{
ds.close(); //消息發送完畢,關閉對象
}
}
}