1. 程式人生 > >java 網路程式設計(Socket) TCP/UDP 總結案例

java 網路程式設計(Socket) TCP/UDP 總結案例

網路程式設計:關注的是底層的資料傳輸

網頁程式設計:資料的展示

1、基本概念


一、網路:將不同的計算機連線在一起區域網 都會網路 網際網路

二、地址:Ip地址確定網路上的絕對的地址位置   房子的地址

三、埠號(相當於房門):區分計算機上的軟體 相當於房門兩個位元組0~65535 共65536個

1、 同一個協議下,埠號不能重複,不同的協議下可以重複

2、 1024以下的埠不要使用 80-->http 21-->ftp

四、資源定位 URL 統一資源定位 URI:統一資源

五、資料的傳輸

1、 協議:TCP UDP協議(重點的)

1)、TCP(transfer control protocol):必須先建立連線 先連線在通訊 電話 類似於三次握手 面向連線 安全可靠 效率相對低下

2)、UDP(UserDatagramProtocol):類似於發簡訊 非面向連線 效率高

現在一般是將兩者結合使用,底層一些不重要的資料使用UDP傳輸

2、 傳輸

1、 先封裝

2、 後拆分


3、資料封裝拆分


1、 InetAddress InetSocketAddress

2、 URL

3、 TCP:serverSocket(建立在伺服器上)  Socket(建立在客戶端上)

4、 UDP: DatagramSocket DatagramPacket

1、InetAddress:封裝IP及DNS

方法:

getHostAddress() 返回ip地址

getHostName() 返回域名|本機為計算機名

InetAddress.getLocalHost();//本機

InetAddress.getByName(“IP地址|域名”);

2、InetSocketAddress:封裝埠

1):建立物件:

InetSocketAddress(String hostname,int port)

InetSocketAddress(InetAddress addr,intport)

2):方法:

getAdddress()

getHostName()

getPort()

<span style="font-size:18px;">package com.net.ip;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * 沒有封裝埠
 * @author lyy
 *
 */
public class InetDemo1 {
	
	public static void main(String[] args) throws UnknownHostException {
		//使用getLoaclHost方法建立InetAddress物件
		InetAddress addr = InetAddress.getLocalHost();
		System.out.println(addr.getHostAddress());//返回ip地址
		System.out.println(addr.getHostName());//輸入計算機名
		//根據域名得到InetAddress物件
		addr = InetAddress.getByName("www.163.com");
		System.out.println(addr.getHostAddress());//返回伺服器的ip地址61.163.117.65
		System.out.println(addr.getHostName()); //輸出 www.163.com
		//根據ip得到InetAddress物件
		addr = InetAddress.getByName("61.163.117.65");//如果ip地址存在而且DNS幫你解析了,那麼getHostName()這個方法返回的就是www.163.com ,否則輸出Ip地址
		System.out.println(addr.getHostAddress());//返回163的伺服器的ip
		System.out.println(addr.getHostName());//輸入Ip而不是域名,如果這個Ip地址不存在
	
	
	}
	</span>
}


<span style="font-size:18px;">package com.net.ip;

import java.net.*;

/**
 * 封裝埠:在InetAddress基礎上+埠
 * @author lyy
 *
 */
public class InetSocketDemo1 {

		public static void main(String[] args) throws UnknownHostException {
			InetSocketAddress address = new InetSocketAddress("127.0.0.1", 9999);
			address= new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 9999);
			System.out.println(address.getHostName());
			System.out.println(address.getPort());
			InetAddress addr = address.getAddress();
			System.out.println(addr.getHostAddress());//返回ip地址
			System.out.println(addr.getHostName());//輸入計算機名
			
			
		}
	
}</span>


3、網路爬蟲原理

URI(Uniform resource identifier) 統一資源識別符號,用唯一的標識一個資源

URL(Uniform resource Locator)統一資源定位器,他是一種具體的URI

四部分組成:協議存放資源的主機域名埠 資原始檔名(/)

URL:

一、建立

URI(String str)//絕對路徑構建

URI(URL context,String spec)//相對路徑構建

二、方法:

System.out.println("協議:"+url.getProtocol());

System.out.println("域名:"+url.getHost());

System.out.println("埠:"+url.getPort());

System.out.println("資源:"+url.getFile());

System.out.println("相對路徑資源:"+url.getPath());

System.out.println("錨點:"+url.getRef());//錨點

System.out.println("引數:"+url.getQuery());//引數:存在錨點回返Null 如果不存在返回引數

<span style="font-size:18px;">package com.net.url;

import java.net.*;

public class URLDemo1 {
	public static void main(String[] args) throws MalformedURLException {
		//絕對路徑構建
		URL url = new URL("http://www.baidu.com:80/index.html#aa?uname=lyy");
		System.out.println("協議:"+url.getProtocol());
		System.out.println("域名:"+url.getHost());
		System.out.println("埠:"+url.getPort());
		System.out.println("資源:"+url.getFile());
		System.out.println("相對路徑資源:"+url.getPath());
		System.out.println("錨點:"+url.getRef());//錨點
		System.out.println("引數:"+url.getQuery());//引數 :存在錨點 返回Null 如果不存在返回引數
		
		
		
		
		
		//相對路徑構建
		url = new URL("http://www.baidu.com:80/a/");
		url = new URL(url,"b.txt");//相對路徑
		System.out.println(url.toString());
	}
}<strong>
</strong></span>
4、通過流讀取資料——OpenStream()
package com.net.url;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.*;

/**
 * 獲取資源:原始碼
 * @author lyy
 * 
 */
public class URLDemo2 {

	public static void main(String[] args) throws IOException {
		URL url = new URL("http://www.baidu.com/");//主頁預設資源
	
		//獲取資源 網路流
//		InputStream is = url.openStream();
//		byte[] flush = new byte[1024];
//		int len = 0;
//		while(-1 != (len = is.read(flush))){
//			System.out.println(new String(flush,0,len));
//		}
//		is.close();
		
		BufferedReader br = 
				new BufferedReader(new InputStreamReader(url.openStream(),"utf-8"));
		BufferedWriter bw = 
				new BufferedWriter(new OutputStreamWriter(new FileOutputStream("baidu.html"),"utf-8"));
		
		String msg = null;
		while((msg = br.readLine()) != null){
			bw.append(msg);
			bw.newLine();
			
		}
		bw.flush();
		br.close();
		bw.close();
	}

}
5、UDP通訊

UDP:以資料為中心 非面向連線 不安全 資料可能丟失 效率高

一、類 DatagramSocketDatagramPacket

1、 客戶端:

1)、建立客戶端DatagramSocket 類 +指定埠

2)、準備資料位元組陣列

3)、打包 datagramPacket  + 伺服器地址和埠

4)、傳送

5)、釋放資源

2、 服務端

a)      建立服務端 DatagramSocket類 +指定埠

b)      準備接收的容器位元組陣列 封裝datagramPacket 

c)       包接收資料

d)      分析資料

e)      釋放資源

典型的b/s 先從伺服器下載源到瀏覽器(客戶端)

<span style="font-size:18px;">package com.net.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * 服務端
 * 1 建立服務端 + 埠
 * 2 準備接收容器
 * 3 封裝成包
 * 4 接收資料
 * 5 分析資料
 * @author lyy
 *
 */
public class MyServer {
		public static void main(String[] args) throws IOException {
//			1 建立服務端 + 埠
			DatagramSocket server = new DatagramSocket(8888);
//			2 準備接收容器
			byte[] container = new byte[1024];
//			3 封裝成包 DatagramPacket(byte[] buf, int length)
			DatagramPacket packet = new DatagramPacket(container, container.length);
//			4 接收資料
			server.receive(packet);
//			5 分析資料
			byte[] data = packet.getData();
			int len = packet.getLength();
			System.out.println(new String(data,0,len));
			//釋放資源
			server.close();
			
		}
}</span>


<span style="font-size:18px;">package com.net.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

/**
 * 客戶端
 * 1 建立客戶端 + 埠
 * 2 準備資料
 * 3 打包(傳送的地點 以及埠)
 * 4 傳送
 * 5 釋放
 * 
 * @author lyy
 *
 */
public class MyClient {

	public static void main(String[] args) throws IOException {
//		1 建立客戶端 + 埠
		DatagramSocket client = new DatagramSocket(6666);
//		2 準備資料
		String msg = "真的愛你";
		byte[] data = msg.getBytes();
//		3 打包(傳送的地點 以及埠) DatagramPacket(byte[] buf, int length, InetAddress address, int port) 
		DatagramPacket packet = new DatagramPacket(data, data.length,new InetSocketAddress("localhost",8888));
//	    4 傳送
		client.send(packet);
//		5 釋放
		client.close();
		
		
	}
	
}
</span>
6、Scoket通訊

基於TCP:面向連線安全 可靠 效率低 類似於打電話

一、面向連線:請求 響應 Request——Response

二、Socket 程式設計

         1、伺服器ServerSocket      

         2、客戶端 Socket


package com.net.tcp.socket;

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 必須先啟動伺服器 後連線
 * 1 建立伺服器 指定埠
 * 2 接收客戶端連線
 * 3 傳送資料和接收資料
 * 
 *   接收多個客戶端
 * @author lyy
 *
 */
public class MultServer {

	public static void main(String[] args) throws IOException {
		//1 建立服務區 指定埠 ServerSocket(int port) 
		ServerSocket server = new ServerSocket(8888);
		// 2 接收客戶端連線 阻塞式
		while(true){//死迴圈 一個accept() 一個客戶端
		Socket socket = server.accept();
		System.out.println("一個客戶端建立連線");
		// 3 傳送資料
		String msg = "歡迎使用";

		DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
		dos.writeUTF(msg);
		dos.flush();
			while(true){
				
			}
		}
	}

}


package com.net.tcp.socket;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 1 建立客戶端 必須指定伺服器 + 埠 此時連線
 * 			Socket(InetAddress host, int port) 
 *  接收資料 傳送資料
 * @author lyy
 *
 */
public class Client {

	public static void main(String[] args) throws UnknownHostException, IOException {
		// 1 、建立客戶端 必須指定伺服器 + 埠 此時連線
		Socket client = new Socket("192.168.1.112", 8888);
		// 2 接收資料
//		BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));
//		String echo = br.readLine();//阻塞式的方法
//		System.out.println(echo);
		DataInputStream dis = new DataInputStream(client.getInputStream());
		String echo = dis.readUTF();
		System.out.println(echo);
		
		
	}
}


7、小案例(強烈建議大家自己敲一遍,很好玩!)

使用的多執行緒、流以及socket通訊原理的方式,建立了一個公眾聊天室的demo,進入有系統提示,可以@名字說悄悄話等等,對socket整個知識點稍微瞭解了更加深入一點點,還是要多消化消化,今天做了一天了,頭有點大了,不說了上案例

package com.net.tcp.chat.demo4;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

/**
 * 建立伺服器
 * @author lyy
 *
 */
public class Server {
	private List<MyChanel> all = new ArrayList<MyChanel>();

	public static void main(String[] args) throws IOException {
		new Server().start();
	}
	
	public void start() throws IOException{
		ServerSocket server = new ServerSocket(9999);
		while(true){
			Socket client =  server.accept();
			MyChanel channel = new MyChanel(client);
			all.add(channel);//加入到容器中同意管理
			new Thread(channel).start();//一條道路
		}
	}
	
	/**
	 * 一個客戶端一個道路
	 * 1 輸入流
	 * 2 輸出流
	 * 3 接收資料
	 * 4 傳送資料
	 * @author lyy
	 *
	 */
	private class MyChanel implements Runnable{
		private DataInputStream dis;
		private DataOutputStream dos;
		private boolean isRunning = true;
		private String name;
		
		public MyChanel(Socket client) {
			 try {
				dis = new DataInputStream(client.getInputStream());
				 dos = new DataOutputStream(client.getOutputStream());
				 
				 this.name = dis.readUTF();
				 this.send("歡迎你進入聊天室!");
				 sendOthers(this.name+"進入了聊天室",true);
			} catch (IOException e) {
				CloseUtil.closeAll(dis,dos);
				isRunning = false;
			}
		
		}
		
		/**
		 * 讀取資料
		 * @return
		 */
		private String receive(){
			String msg = "";
			try {
				msg = dis.readUTF();
			} catch (IOException e) {
				CloseUtil.closeAll(dis);
				isRunning = false;
				all.remove(this);//移除自身
			}
			return msg;
		}
		
		/**
		 * 傳送資料
		 */
		public void send(String msg){
			if(null == msg && !msg.equals("")){
				return;
			}
			try {
				dos.writeUTF(msg);
				dos.flush();
			} catch (IOException e) {
//				e.printStackTrace();
				CloseUtil.closeAll(dos);
				isRunning = false;
				all.remove(this);//移除自身
			}
		}
		
		/**
		 * 傳送給其他客戶端
		 */
		private void sendOthers(String msg,boolean sys){
			System.out.println(msg);
			//是否為私聊 約定
			if(msg.startsWith("@") && msg.indexOf(":") > -1){//表示私聊
				String name = msg.substring(1, msg.indexOf(":"));
				String conetnt = msg.substring(msg.indexOf(":")+1);
				//獲取Name
				for (MyChanel other : all) {
					if(other.name.equals(name)){
						other.send(this.name+"對您悄悄說"+conetnt);
					}
				}
			}else{
			
			//遍歷容器
			for (MyChanel other : all) {
				if(other == this){
					continue;
				}
				if(sys){//系統資訊
					//傳送給其他客戶端
					other.send("系統資訊:"+msg);
				}else{
					//傳送給其他客戶端
					other.send(this.name+":"+msg);
				}
				
			}
			}
		}
		
		@Override
		public void run() {
			while(isRunning){
				sendOthers(receive(),false);
			}
		}
		
	}
	
}

package com.net.tcp.chat.demo4;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

/**
 * 傳送資料執行緒
 * @author lyy
 *
 */
public class Send implements Runnable{

	//控制檯的輸入流
	private BufferedReader console;
	//管道輸出流
	private DataOutputStream dos;
	//控制執行緒
	private boolean isRunning = true;
	//名稱
	private String name;
	public Send() {
		console = new BufferedReader(new InputStreamReader(System.in));
	}
	
	public Send(Socket client , String name){
		this();
		 try {
			dos = new DataOutputStream(client.getOutputStream());
			this.name = name;
			send(this.name);
		} catch (IOException e) {
//			e.printStackTrace();
			isRunning = false;
			CloseUtil.closeAll(dos,console);
			
		}
	}
	
	//從控制檯接收資料
	private  String getMsgFromConsole(){
		try {
			return console.readLine();
		} catch (IOException e) {
			e.printStackTrace();
		
		}
		return "";
	}
	/**
	 * 從控制檯接收資料
	 * 傳送資料
	 */
	public void send(String msg){
		if(msg != null && !msg.equals("")){
			try {
				dos.writeUTF(msg);
				dos.flush();//強制重新整理
			} catch (IOException e) {
//				e.printStackTrace();
				isRunning = false;
				CloseUtil.closeAll(dos,console);
			}
		}
	}
	
	@Override
	public void run() {
		//執行緒體
		while(isRunning){
			send(getMsgFromConsole());
		}
	}

}


package com.net.tcp.chat.demo4;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;

/**
 * 接收執行緒
 * @author lyy
 *
 */
public class Receive implements Runnable{

	//輸入流
	private DataInputStream dis;
	//執行緒標識
	private boolean isRunning = true;
	
	public Receive() {
	}
	public Receive(Socket client){
		try {
			dis = new DataInputStream(client.getInputStream());
		} catch (IOException e) {
//			e.printStackTrace();
			isRunning = false;
			CloseUtil.closeAll(dis);
		}
	}
	
	/**
	 * 接收資料
	 * @return
	 */
	public String receive(){
		String msg ="";
		try {
			msg = dis.readUTF();
		} catch (IOException e) {
			isRunning = false;
			CloseUtil.closeAll(dis);
		}
		return msg;
	}
	
	@Override
	public void run() {
		//執行緒體
		while(isRunning){
			System.out.println(receive());
		}
	}

}


<span style="font-size:18px;">package com.net.tcp.chat.demo4;

import java.io.Closeable;
import java.io.IOException;

/**
 * 關閉流的方法
 * @author lyy
 *
 */
public class CloseUtil {
		public static void closeAll(Closeable... io){
			for(Closeable temp :io){
				if(null != temp){
						try {
							temp.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
				}
			}
		}
	</span>
}


<span style="font-size:18px;">package com.net.tcp.chat.demo4;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 建立客戶端 傳送資料 + 接收資料
 * 寫出資料 輸出流
 * 讀取資料 輸入流
 * @author lyy
 * 
 * 輸入流和輸出流在同一個執行緒內 彼此獨立
 * 
 * 
 *
 */
public class Client {
	
	public static void main(String[] args) throws UnknownHostException, IOException {
		System.out.println("請輸入名稱:");
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String name = br.readLine();
		if(name.equals("")){
			return;
		}
		Socket client = new Socket("localhost", 9999);
		new Thread(new Send(client,name)).start();//一條路徑
		new Thread(new Receive(client)).start();//一條路徑
	}
	
}
</span>

學習了一天,感覺還是有很大的收穫的,需要多消化消化,希望大家也能從中收穫一點自己想要的東西,加油!

總結案例下載:http://download.csdn.net/detail/qq_14996421/9527603