【Java】day24--Udp通信、Tcp通信

(一)Udp通信

網絡通訊協議:
    udp協議
    tcp協議
在java中不管是用哪種協議通信,計算機與計算機之間的通信都統稱爲Socket(插座)通信,通信的兩端 計算機都必須要安裝上Socket。
在不同的協議下應該用不同的Socket.

udp協議的特點
    1.將數據及其源和目的封裝爲數據包,不需要建立連接。
    2.每個數據包大小限制在64k中,基於數據包進行傳輸。
    3.因爲無連接,所以不可靠(會出現數據丟失)。
    4.因爲不需要建立連接,所有速度快。
    5.udp協議不分客戶端與服務器,只分發送端與接收端。
    玩遊戲是udp,卡機其實是數據包丟失。
        比如:對講機、飛Q通信、視頻會議
udp通信:
    DatagramSocket(udp協議的服務類)
    DatagramPacket(數據包類)
    
DatagramPacket(byte[] buf,int length,InetAddress address,int port)
    buf:當前數據的字節數組的表現形式。
    length:字節數組的長度。
    address:發送的ip地址。
    port:端口號。

//udp的發送端
public class demo1 {

	public static void main(String[] args) throws IOException {
		//第一步:建立udp的服務
		DatagramSocket socket=new DatagramSocket();
		//第二步:準備數據,把數據封裝到數據包中
		String data="這個是我的第一個udp的例子!";
		byte[] buf=data.getBytes();
		DatagramPacket packet=new DatagramPacket(buf, buf.length,InetAddress.getLocalHost(),9090);//InetAddress.getByName(ip地址)指定接收端ip地址
		//第三步:調用udp的服務,發送數據
		socket.send(packet);
		//第四步:關閉資源(釋放端口號)(io中關閉資源是釋放資源文件)
		socket.close();
	}
}
//先啓動接收端,再啓動發送端
//udp服務的接收端
public class demo2_receiver {
		
	public static void main(String[] args) throws IOException {
		//第一步:建立udp的服務,並且壓迫監聽一個端口
		DatagramSocket socket=new DatagramSocket(9090);
		//第二步:準備一個空的數據包
		byte[] buf=new byte[1024];
		DatagramPacket packet=new DatagramPacket(buf,buf.length);
		//第三步:調用udp的服務接收數據包,數據其實是存入了字節數組中,數據包依賴於字節數組存儲數據。
		socket.receive(packet);//receive()方法是一個阻塞型方法,如果沒有接收到數據,會一直等待下去
		//Scanner的next方法是阻塞型方法,只有接收到數據纔會繼續進行,否則會一致等待
		System.out.println(packet.getAddress().getHostAddress()+"接收端接收到的數據:"+new String(buf,0,packet.getLength()));//getLength是獲取本次接收到的字節個數);
		//packet.getAddress().getHostAddress()獲取到發送方的ip地址   getAddress是獲取對方的IP地址對象 getHostAddress()獲取ip地址
		//第四步:關閉資源
		socket.close();
	}	
}

udp協議可能導致數據丟失的情況:
    1.帶寬不足。
    2.cpu處理能力不足。

(二)Tcp通信

tcp協議的特點:
    1.面向連接,在傳輸數據之前一定要建立連接,tcp的客戶端一旦建立,馬上要與服務端建立連接。
    2.在連接中可以傳輸大量數據,基於IO流進行傳輸。
    3.通過三次握手機制連接,是可靠協議(保證數據傳輸的完整性)。
    4.因爲tcp是面向連接的,所有效率稍低。
    5.tcp協議分客戶端與服務端。

tcp協議下的Socket:
    Socket(客戶端類)
    ServerSocket(服務端類)
比如:qq文件傳輸、打電話

//客戶端
public class demo1 {
	public static void main(String[] args) throws UnknownHostException, IOException {
		//第一步:建立tcp的客戶端服務
		Socket socket=new Socket(InetAddress.getLocalHost(),9090);
		//第二步:準備數據(基於io流傳輸數據),獲取對應的流 通道
		String data="這是第一個tcp例子";
		//數據相對當前客戶端來說是流出的,用輸出流
		OutputStream outputStream=socket.getOutputStream();
		//第三步:把數據寫出
		outputStream.write(data.getBytes());
		//客戶端要接收服務端回送的數據
			//獲取socket的輸入流
		InputStream input=socket.getInputStream();
		byte[] buf=new byte[1024];
		int length=input.read(buf);
		System.out.println("客戶端接收到的內容:"+new String(buf,0,length));
		//第四步:關閉資源
		//outputStream.close();//io中關閉輸出流是因爲佔用了文件資源,這裏不需要關,從socket中獲得,直接關socket即可
		socket.close();
	}
}
//先啓動服務端,再啓動接收端
//服務端 ServerSocket
public class demo2_server {

	public static void main(String[] args) throws IOException {
		//第一步:建立tcp的服務端
		ServerSocket serverSocket=new ServerSocket(9090);
		//第二步:接受客戶端的連接
		Socket socket=serverSocket.accept();//accept是阻塞型方法,沒有客戶端與其連接時,一直等待下去。
		//第三步:獲取對應的輸入流通道
		InputStream inputStream=socket.getInputStream();
		//第四步:通過輸入流通道讀取數據
		byte[] buf=new byte[1024];
		int length=inputStream.read(buf);
		System.out.println("服務端接收到的數據:"+new String(buf,0,length));
		//服務端給客戶端回送數據
			//獲取socket的輸出流
		OutputStream output=socket.getOutputStream();
		output.write("客戶端辛苦啦。。".getBytes());
		//第五步:關閉資源
		serverSocket.close();
	}
}

練習:

/*
一個服務端可以與多個客戶端連接。
需求:編寫一個服務端可以與多個客戶端進行連接,客戶端一旦連接成功,馬上輸送一張圖片數據給客戶端。
	再統計接收到的客戶端數,同一個客戶端只算一次。

服務端需要多線程
*/
//多線程服務端 提供圖片
public class demo3 extends Thread{

	Socket socket;
	static HashSet ips=new HashSet();
	public demo3(Socket socket) {
		this.socket=socket;
	}
	@Override
	public void run() {
		try {
			//第一步:建立tcp服務端的服務
			//ServerSocket serverSocket=new ServerSocket(9090);
			//第二步:接收用戶的請求連接
			//Socket socket=serverSocket.accept();
			//第三步:獲取Socket輸出字節流(服務端輸出圖片)
			OutputStream socketOut=socket.getOutputStream();
			//第四步:獲取文件的輸入流,讀物文件的數據,把文件數據寫出給客戶端
			FileInputStream fileInputStream=new FileInputStream("E:\\1.jpg");
			byte[] buf=new byte[1024];
			int length=0;
			while((length=fileInputStream.read(buf))!=-1) {
				socketOut.write(buf,0,length);
			}
			String ip=socket.getInetAddress().getHostAddress();//獲取到對方(接收方)的ip地址
			if(ips.add(ip)) {//如果可以存儲到集合中,意味着這是一個新的ip地址
				System.out.println("恭喜"+ip+"下載成功、、");
				System.out.println("當前下載的人數:"+ips.size());
			}
				//第五步:關閉資源
			fileInputStream.close();
			socket.close();//每個socket都會佔用端口,用完需關閉
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	public static void main(String[] args) throws IOException {
		//第一步:建立tcp服務端的服務,只需要一個服務端對象
		ServerSocket serverSocket=new ServerSocket(9090);
		while(true) {
			Socket socket=serverSocket.accept();//不斷地接收用戶的連接請求
			new demo3(socket).start();//如果產生了一個Socket就意味着有一個客戶與服務端連接,馬上開啓一個線程爲其服務
		}
	}
}
//客戶端接收圖片
public class demo4 {

	public static void main(String[] args) throws IOException {
		//建立tcp的客戶端服務
		Socket socket=new Socket(InetAddress.getLocalHost(),9090);//客戶端寫的是本機
		//獲取socket的輸入流對象
		InputStream inputStream=socket.getInputStream();
		//建立一個文件的輸出字節流對象
		FileOutputStream fileOutputStream=new FileOutputStream("E:\\小貓.jpg");
		//邊讀邊寫
		byte[] buf=new byte[1024];
		int length=0;
		while((length=inputStream.read(buf))!=-1) {
			fileOutputStream.write(buf,0,length);
		}
		//關閉資源
		fileOutputStream.close();
		socket.close();
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章