The First Daily Scrum Meeting
網路程式設計是指編寫執行在多個裝置(計算機)的程式,這些裝置都通過網路連線起來。
java.net
包中提供了低層次的網路通訊細節。你可以直接使用這些類和介面,來專注於解決問題,而不用關注通訊細節。
java.net 包中提供了兩種常見的網路協議的支援:
- TCP - TCP 是傳輸控制協議的縮寫,它保障了兩個應用程式之間的可靠通訊。通常用於網際網路協議,被稱 TCP/ IP。
- UDP - UDP 是使用者資料報協議的縮寫,一個無連線的協議。提供了應用程式之間要傳送的資料的資料包。
一、Socket 和 ServerSocket
套接字(Socket)使用 TCP 提供了兩臺計算機之間的通訊機制。 客戶端程式建立一個套接字,並嘗試連線伺服器的套接字。
Java 通過 Socket 和 ServerSocket 實現對 TCP 的支援。Java 中的 Socket 通訊可以簡單理解為:java.net.Socket
代表客戶端,java.net.ServerSocket
代表服務端,二者可以建立連線,然後通訊。
以下為 Socket 通訊中建立建立的基本流程:
- 伺服器例項化一個
ServerSocket
物件,表示伺服器繫結一個埠。 - 伺服器呼叫
ServerSocket
的accept()
方法,該方法將一直等待,直到客戶端連線到伺服器的繫結埠(即監聽埠)。 - 伺服器監聽埠時,客戶端例項化一個
Socket
物件,指定伺服器名稱和埠號來請求連線。 Socket
類的建構函式試圖將客戶端連線到指定的伺服器和埠號。如果通訊被建立,則在客戶端建立一個 Socket 物件能夠與伺服器進行通訊。- 在伺服器端,
accept()
方法返回伺服器上一個新的Socket
引用,該引用連線到客戶端的Socket
。
連線建立後,可以通過使用 IO 流進行通訊。每一個 Socket
都有一個輸出流和一個輸入流。客戶端的輸出流連線到伺服器端的輸入流,而客戶端的輸入流連線到伺服器端的輸出流。
TCP 是一個雙向的通訊協議,因此資料可以通過兩個資料流在同一時間傳送,以下是一些類提供的一套完整的有用的方法來實現 sockets。
ServerSocket
伺服器程式通過使用 java.net.ServerSocket
ServerSocket 構造方法
ServerSocket
有多個構造方法:
方法 | 描述 |
---|---|
ServerSocket() |
建立非繫結伺服器套接字。 |
ServerSocket(int port) |
建立繫結到特定埠的伺服器套接字。 |
ServerSocket(int port, int backlog) |
利用指定的 backlog 建立伺服器套接字並將其繫結到指定的本地埠號。 |
ServerSocket(int port, int backlog, InetAddress address) |
使用指定的埠、監聽 backlog 和要繫結到的本地 IP 地址建立伺服器。 |
ServerSocket 常用方法
建立非繫結伺服器套接字。 如果 ServerSocket
構造方法沒有丟擲異常,就意味著你的應用程式已經成功繫結到指定的埠,並且偵聽客戶端請求。
這裡有一些 ServerSocket
類的常用方法:
方法 | 描述 |
---|---|
int getLocalPort() |
返回此套接字在其上偵聽的埠。 |
Socket accept() |
監聽並接受到此套接字的連線。 |
void setSoTimeout(int timeout) |
通過指定超時值啟用/禁用 SO_TIMEOUT ,以毫秒為單位。 |
void bind(SocketAddress host, int backlog) |
將 ServerSocket 繫結到特定地址(IP 地址和埠號)。 |
Socket
java.net.Socket
類代表客戶端和伺服器都用來互相溝通的套接字。客戶端要獲取一個 Socket
物件通過例項化 ,而 伺服器獲得一個 Socket
物件則通過 accept()
方法 a 的返回值。
Socket 構造方法
Socket
類有 5 個構造方法:
方法 | 描述 |
---|---|
Socket() |
通過系統預設型別的 SocketImpl 建立未連線套接字 |
Socket(String host, int port) |
建立一個流套接字並將其連線到指定主機上的指定埠號。 |
Socket(InetAddress host, int port) |
建立一個流套接字並將其連線到指定 IP 地址的指定埠號。 |
Socket(String host, int port, InetAddress localAddress, int localPort) |
建立一個套接字並將其連線到指定遠端主機上的指定遠端埠。 |
Socket(InetAddress host, int port, InetAddress localAddress, int localPort) |
建立一個套接字並將其連線到指定遠端地址上的指定遠端埠。 |
當 Socket 構造方法返回,並沒有簡單的例項化了一個 Socket 物件,它實際上會嘗試連線到指定的伺服器和埠。
Socket 常用方法
下面列出了一些感興趣的方法,注意客戶端和伺服器端都有一個 Socket 物件,所以無論客戶端還是服務端都能夠呼叫這些方法。
方法 | 描述 |
---|---|
void connect(SocketAddress host, int timeout) |
將此套接字連線到伺服器,並指定一個超時值。 |
InetAddress getInetAddress() |
返回套接字連線的地址。 |
int getPort() |
返回此套接字連線到的遠端埠。 |
int getLocalPort() |
返回此套接字繫結到的本地埠。 |
SocketAddress getRemoteSocketAddress() |
返回此套接字連線的端點的地址,如果未連線則返回 null。 |
InputStream getInputStream() |
返回此套接字的輸入流。 |
OutputStream getOutputStream() |
返回此套接字的輸出流。 |
void close() |
關閉此套接字。 |
Socket 通訊示例
//伺服器端
public class ServiceDemo1 {
public static void main(String[] args) throws IOException {
//在伺服器端監聽8888埠
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("伺服器執行中,等待客戶端連線");
//得到客戶端連線,伺服器會阻塞,直到有一個客戶端連線
Socket client = serverSocket.accept();
//獲取客戶端輸出流
OutputStream outputStream = client.getOutputStream();
String str = "hello world";
outputStream.write(str.getBytes());
outputStream.flush();
client.close();
serverSocket.close();
System.out.println("伺服器訊息傳送完畢,退出");
}
}
//客戶端
public class ClientDemo1 {
public static void main(String[] args) throws IOException {
Socket client = new Socket("localhost",8888);
InputStream inputStream = client.getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(reader);
String str = bufferedReader.readLine();
System.out.println(str);
bufferedReader.close();
reader.close();
inputStream.close();
System.out.println("客戶端接受完畢");
}
}
//使用字元流來傳輸資料
public class TCPClient1 {
public static void main(String[] args) throws IOException {
Socket client = new Socket(InetAddress.getLocalHost(),8888);
OutputStream outputStream = client.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
writer.write("hello server! 無涯子");
writer.newLine();//結束標識
writer.flush();
//得到伺服器端響應
InputStream inputStream = client.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String s = reader.readLine();
System.out.println(s);
//關閉流資源
reader.close();
inputStream.close();
writer.close();
outputStream.close();
client.close();
}
}
public class TCPServer2 {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8888);
System.out.println("伺服器已經開啟埠8888等待連線");
Socket client = server.accept();
InputStream inputStream = client.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String s = reader.readLine();
System.out.println(s);
OutputStream outputStream = client.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
writer.write("hello client! 無涯子");
writer.newLine();
writer.flush();
//關閉流資源
writer.close();
outputStream.close();
reader.close();
inputStream.close();
client.close();
server.close();
}
}
二、DatagramSocket 和 DatagramPacket
Java 通過 DatagramSocket
和 DatagramPacket
實現對 UDP 協議的支援。
DatagramPacket
:資料包類DatagramSocket
:通訊類
//UPD通訊伺服器
public class UDPServer {
public static void main(String[] args) throws Exception {
String str = "hello world";
//伺服器在埠3000等待發送到伺服器的訊息
DatagramSocket datagramSocket = new DatagramSocket(3000);
DatagramPacket datagramPacket = new DatagramPacket(str.getBytes(),str.length(),
InetAddress.getByName("localhost"),9000);
System.out.println("傳送訊息");
datagramSocket.send(datagramPacket);
datagramSocket.close();
}
}
public class UDPClient {
public static void main(String[] args) throws Exception{
byte[] buf = new byte[1024];//開闢空間,接受資料
DatagramSocket ds = new DatagramSocket(9000);
DatagramPacket dp = new DatagramPacket(buf,1024);//所有資訊使用buf儲存
ds.receive(dp);
String str = new String(dp.getData(),0,dp.getLength()) + "from " +
dp.getAddress().getHostAddress() + ":" + dp.getPort();
System.out.println(str);
ds.close();
}
}
public class UDPClient1 {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(3000);
System.out.println("傳送端開啟UDP3000埠");
byte[] data = "hello,明天去吃火鍋".getBytes();
//第三個引數也可以是ip地址,因為這裡是進行本地測試所以是localhost
DatagramPacket dp = new DatagramPacket(data,data.length, InetAddress.getByName("localhost"),9999);
ds.send(dp);
//接受資料
ds.receive(dp);
int len = dp.getLength();
System.out.println(new String(dp.getData(),0,len));
ds.close();
}
}
public class UDPServer1 {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(9999);
System.out.println("接受端開啟UDP9999埠");
byte[] data = new byte[1024];
DatagramPacket dp = new DatagramPacket(data,data.length);
ds.receive(dp);
System.out.println(new String(dp.getData(),0,dp.getLength()));
//響應資料
data = "ok,沒問題".getBytes();
dp = new DatagramPacket(data,data.length, InetAddress.getByName("localhost"),3000);
ds.send(dp);
ds.close();
}
}
三、InetAddress
InetAddress
類表示網際網路協議(IP)地址。
沒有公有的建構函式,只能通過靜態方法來建立例項。
四、URL
public class URLDemo1 {
public static void main(String[] args) throws Exception {
URL url = new URL("http://www.baidu.com");
InputStream inputStream = url.openStream();
InputStreamReader is = new InputStreamReader(inputStream,"utf-8");
BufferedReader reader = new BufferedReader(is);
String line;
while((line = reader.readLine()) != null){
System.out.println(line);
}
reader.close();
is.close();
inputStream.close();
}
}