socket:兩個Java應用程序可通過一個雙向的網絡通信連接實現數據交互,這個雙向鏈路的一端稱爲一個socket
1.socket通信模型之TCP協議:
java.net包中定義的兩個類Socket和ServerSocket,分別用來是實現雙向鏈接的client端和server端
代碼實現:
客戶端:
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1", 6666);//創建socket客戶端,並設置監聽地址及端口
//向服務端發出消息
OutputStream outputStream = socket.getOutputStream();//因爲客戶端是要向服務端發出消息,即寫出,因此使用OutputStream()來向socket服務端發送消息
DataOutputStream dos = new DataOutputStream(outputStream);//爲了方便我們直接寫入字符或數字類型,使用數據流DataOutputStream()對輸出流OutputStream()進行封裝
dos.writeUTF("Hello Server!");//向輸出流中寫入UTF編碼的字符串
//接收服務端的消息
InputStream inputStream = socket.getInputStream(); //接收服務端發出的消息對於客戶端來說爲寫入,因此使用InputStream()來接收socket服務端發送的消息
InputStreamReader isr = new InputStreamReader(inputStream);//轉換爲字符流
BufferedReader br = new BufferedReader(isr);//轉換爲緩衝流,從而使用緩衝流的readLine()方法直接讀取一行
System.out.println(br.readLine());
dos.flush();//將輸出流管道中的數據做一次推送,保證完全發出去
dos.close();//關閉輸出流
isr.close();//關閉輸入流
socket.close();//關閉socket
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
服務端:
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(6666);//創建socket服務端,並設置端口號
Socket socket = serverSocket.accept();//accept()爲接受來自客戶端的請求連接信息,此方法爲阻塞式方法,即沒有客戶端連接的情況下,會一直阻塞在此處,不會往下執行
System.out.println("連接成功");
//接收客戶端的消息
InputStream inputStream = socket.getInputStream();//接收客戶端消息,即爲寫入,因此使用InputStream()來接收Socket客戶端發來的消息
DataInputStream dis = new DataInputStream(inputStream);//爲了方便我們直接讀取字符或數字類型,使用數據流DataInputStream()對輸入流InputStream()進行封裝
String result = dis.readUTF();
System.out.println("收到來自:"+socket.getInetAddress()+":"+socket.getPort()+"的消息:"+result);
//向客戶端發出消息
OutputStream outputStream = socket.getOutputStream();//向Socket客戶端發出消息
OutputStreamWriter osw = new OutputStreamWriter(outputStream);
osw.write("Hello Client!");
osw.flush();
osw.close();
dis.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
注意:啓動時,需要先啓動服務端,後啓動客戶端
2.Socket通信模型之UDP協議:
UDP協議下來說,是沒有客戶端和服務端之說的,分爲消息的發送方和接收方。
代碼實現:
發送方:
public static void main(String[] args) {
long message = 10000L; //定義要傳送的“消息”
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();//在內存中創建一塊字節數組區域,用以存放字節數組,並將其轉換爲字節數組,ByteArrayOutputStream()主要作用爲將數據轉爲字節數組
DataOutputStream dos = new DataOutputStream(baos);//使用數據流DataOutputStream來寫入double/int/float/long等數字類型到字節數組
dos.writeLong(message); //將數據寫入到字節數組中,以便於轉換爲字節數組
dos.flush();
dos.close();
byte buf[] = baos.toByteArray();//將剛剛在內存中創建並存放數據的字節數組中的字節數組獲取出來
DatagramPacket dp = new DatagramPacket(buf,0,buf.length,new InetSocketAddress("127.0.0.1",6789));//UDP協議發出或接收數據需要使用數據包來對數據做一個包裹,因此創建數據包用於包裹字節數組,需註明使用的數組、數組中數據長度
DatagramSocket ds = new DatagramSocket(9876);//創建UDP協議的Socket對象用以傳輸數據,並設置自己端口號
ds.send(dp);//send()發送消息
ds.close();
}catch (IOException e)
{
e.printStackTrace();
}
}
接收方:
public static void main(String[] args) {
try {
byte buf[] = new byte[1024];//定義長度爲1024的字節數組,用於存放字節信息
DatagramSocket ds = new DatagramSocket(6789);//創建UDP協議的Socket對象用以傳輸數據,並設置自己端口號
DatagramPacket dp = new DatagramPacket(buf,0,buf.length);//UDP協議發出或接收數據需要使用數據包來對數據做一個包裹,因此創建數據包用於包裹字節數組,需註明使用的數組、數組中數據長度
ds.receive(dp);//receive()用以接收發送端發出的消息
//以上操作爲,定義數據載體字節數組以及一個DatagramPacket()來包裹字節數組,DatagramSocket()使用DatagramPacket()來接收數據,最終數據會被存放在buf[]中
//下邊對buf[]中的數據進行讀取
ByteArrayInputStream bais = new ByteArrayInputStream(buf);//在內存中創建一塊字節數組區域,用以存放字節數組
DataInputStream dis = new DataInputStream(bais);//使用數據流DataInputStream來讀取double/int/float/long等數字類型到字節數組
long message = dis.readLong(); //讀取
System.out.println("接收到的消息爲:"+message);
dis.close();
ds.close();
}catch (IOException e)
{
e.printStackTrace();
}
}
注:
1.UDP在傳輸信息時需將消息轉爲字節數組放到數據包DatagramPacket(),上邊使用的ByteArrayInputStream()和ByteArrayOutputStream()是在內存中開闢一塊區域用於存放字節數組,目的是爲了將數字類型的消息轉爲字節數組,使用其提供的toByteArray()即可實現:
2.但是如果我們傳輸的是字符類型的話,可直接使用String提供的getBytes()來得到對應的字節數組: