TCP通信 -聊天室版本2
案例
案例:實現客戶端可以重複從控制檯輸入數據,服務器端不停的接受數據並打印到控制檯,直到輸入”886”,客戶端斷開連接.
分析:1.先完成客服端向服務端發送數據,在服務器端將接受到的數據打印到控制檯
2. TCP通信, 網絡通信(三要素:IP,端口號,通信協議)
1). IP:InetAddress
2) 端口號:0-65536
3). 通信協議:TCP UDP
3. TCP通信
i. Socket套接字:客戶端的套接字(端點)
ii. ServerSocket套接字:服務器端的套接字
iii. 數據傳輸:
1. IO流,從Socket中獲取相對應的流對象
2. 遵循TLD協議 - DataStream
4.重複發送數據,需要用到循環while(true){ …….. } ,要知道流創建不需要放在循環體內;另外客戶端不斷髮送數據,服務端要不斷的接收數據,所以服務端也要用到循環;當客戶端最後一次輸入“886”時,客戶端的socket關閉,在服務端捕獲異常,如果客戶端socket關閉提示客戶端已下線了。
package tedu.cn_socket通信_聊天室版本2;
/*
* 客戶端發數據到服務端
* 1.Tcp傳輸,客戶端建立的過程.
* 創建tcp客戶端socket服務,使用的是socket對象
* 建議該對象一創建就明確目的地,要連接的主機.
* 2.如果連接建立成功,說明數據傳輸通道已建立。
* 該通道就是socket流,是底層建立好的。既然是流,說明這裏既有輸入,又有輸出。
* 想要輸入或輸出流對象,可以找Socket來獲取。
* 可以通過getOutputStream(),和getInputStream()來獲取兩個字節流
* 3.使用輸出流,將數據寫出。
* 4.關閉資源
*/
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/*
* 1.使用Socket與ServerSocket建立客戶端與服務端的連接,並使客戶端向服務端發送一條消息。
*/
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
//創建客戶端Socket對象
//連接目標服務器的地址,localhost是目標服務器的地址,10086是目標服務器的端口
Socket socket = new Socket("localhost",10086);
System.out.println("我是:"+socket.getLocalPort());
Scanner sc = new Scanner(System.in);
//獲取Socket流中的輸出流,向服務器輸出消息,即發消息到服務器
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
while(true){
//寫發送數據的大小
String data = sc.nextLine();
byte[] bys=data.getBytes("utf-8");
//寫數據-遵循TLD協議 1:文本數據 2:圖片數據 3:音頻數據
//寫發送的數據類型
dos.writeByte(1);
//發送數據長度
dos.writeInt(bys.length);
//寫要發送的數據 通常用了流之後要關閉的close()但是這裏不用
dos.write(bys);
dos.flush();//刷新
//判斷
if("886".equals(data)){
break;
}
}
//斷開連接 客戶端下線 (所有的流也關閉)
sc.close();
socket.close();
}
}
package tedu.cn_socket通信_聊天室版本2;
/*
* 服務端接收客戶端發過來的數據,並打印在控制檯上。
* 建立tcp服務端的思路:
* 1.創建服務端Soket服務,通過ServerSocket對象
* 2.服務端必須對外提供一個端口,否則客戶端無法連接
* 3.獲取連接過來的客戶端對象
* 4.通過客戶端對象獲取socket流讀取客戶端發來的數據
* */
import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
static ServerSocket ss;
static Socket socket;
//static byte type;
//UDP:發送端、接收端(無連接)
//TCP:客戶端、服務端(要連接)先啓動服務端,再啓動客戶端
public static void main(String[] args) {
try{
//創建服務端對象
ss = new ServerSocket(10086);
//監聽應用所在服務器的10086端口
//看有沒有客戶端連接過來,或者發送消息
//建立連接,獲取鏈接過來的客戶端對象
socket=ss.accept(); //接受客戶端請求,
DataInputStream dis = new DataInputStream(socket.getInputStream());
while(true){
int port =socket.getPort();//客戶端端口
//通過socket對象獲取輸入流,要讀取客戶端發來的數據
//接收數據類型
byte type=dis.readByte();
//根據type判斷進行一些操作
//接收數據長度
int len = dis.readInt();
//接收數據內容
byte[] bys = new byte[len];
dis.read(bys);
System.out.println(port+":說"+(new String(bys,"utf-8")));
}
}catch(IOException e){
try {
socket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
System.out.println("客戶端下線了");
}
}
}
運行結果
先運行服務端,後運行客戶端