* java.net.InetAddress:此類表示互聯網協議 (IP) 地址。
*
* 兩個靜態方法:可以獲取InetAddress對象
* static InetAddress getLocalHost() 返回本地(自己使用的電腦 127.0.0.1)主機。
* static InetAddress getByName(String host) 在給定主機名或IP地址的情況下確定主機的InetAddress地址。
* 兩個非靜態的方法:分別獲取IP地址和主機名
* String getHostAddress() 返回 IP 地址字符串(以文本表現形式)。
* String getHostName() 獲取此 IP 地址的主機名。
*/
eg:InetAddress inet = InetAddress.getLocalHost();
String ip = inet.getHostAddress();
String name = inet.getHostName();
eg:InetAddress inet = InetAddress.getByName("www.baidu.cn");
String ip = inet.getHostAddress();
String name = inet.getHostName();
在介紹TCP/IP結構時,提到傳輸層的兩個重要的高級協議,分別是UDP和TCP,其中:
UDP是User Datagram Protocol的簡稱,稱爲用戶數據報協議,數據報:網絡傳輸的基本單位。
TCP是Transmission Control Protocol的簡稱,稱爲傳輸控制協議。
/*
* UDP通信的接收端:接收發送端的數據報包,拆包
* java.net.DatagramPacket:此類表示數據報包。接收發送端的數據報包
* java.net.DatagramSocket:此類表示用來發送和接收數據報包的套接字。 (碼頭)
*
* 構造方法:
* DatagramPacket(byte[] buf, int length) 構造 DatagramPacket,用來接收長度爲 length 的數據包。
* 封裝字節數組,接收發送端的數據報包
* DatagramSocket(int port) 創建數據報套接字並將其綁定到本地主機上的指定端口。
* 和系統要指定的端口號
*
* 成員方法:
* void receive(DatagramPacket p) 從此套接字接收數據報包。
*
* 實現步驟:
* 1.創建DatagramPacket對象,接收發送端的數據報包
* 2.創建DatagramSocket對象,綁定指定的端口號
* 3.調用DatagramSocket中的方法receive接收發送端的數據報包
* 4.拆包
* DatagramPacket:有拆包的方法
* int getLength() 獲取發送端發送數據的長度
* InetAddress getAddress() 獲取發送端的IP地址對象
* int getPort() 獲取發送端的端口號
* 5.釋放資源
*
* 永久等待特性,不收到數據,程序不終止
*/
public class UDPReceive {
public static void main(String[] args) throws IOException {
// 1.創建DatagramPacket對象,接收發送端的數據報包
byte[] bytes = new byte[1024];// 最大 64*1024 64kb
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
// 2.創建DatagramSocket對象,綁定指定的端口號
DatagramSocket ds = new DatagramSocket(8888);
while (true) {
// 3.調用DatagramSocket中的方法receive接收發送端的數據報包
ds.receive(dp);
// 4.拆包 int getLength() 獲取發送端發送數據的長度
int length = dp.getLength();
// InetAddress getAddress() 獲取發送端的IP地址對象
InetAddress inet = dp.getAddress();
// int getPort() 獲取發送端的端口號
int port = dp.getPort();// 系統隨機分配給發送端
System.out.println(new String(bytes, 0, length) + "..."
+ inet.getHostAddress() + ":" + port);
}
// 5.釋放資源
// ds.close();
}
}
/*
* UDP:面向無連接,不需要連接,直接發送
* UDP通信的發送端:把數據包裝,發送到接收端
* java.net.DatagramPacket:此類表示數據報包。(集裝箱)封裝要傳輸的數據,封裝接收端的IP地址,封裝接收端的端口號
* java.net.DatagramSocket:此類表示用來發送和接收數據報包的套接字。 (碼頭)
*
* 構造方法:
* DatagramPacket(byte[] buf, int length, InetAddress address, int port)
* 構造數據報包,用來將長度爲 length 的包發送到指定主機上的指定端口號。
* 封裝要傳輸的數據,封裝接收端的IP地址,封裝接收端的端口號
* DatagramSocket() 構造數據報套接字並將其綁定到本地主機上任何可用的端口。
* 系統隨機給發送端分配端口號
*
* 成員方法:
* void send(DatagramPacket p) 從此套接字發送數據報包。 發送數據報包到接收端
* 套接字:封裝了IP地址和端口號的網絡軟件
*
* 實現步驟:
* 1.創建DatagramPacket對象,封裝要傳輸的數據,封裝接收端的IP地址,封裝接收端的端口號
* 2.創建DatagramSocket對象,用來發送數據報包
* 3.調用DatagramSocket對象中的send方法,把數據報包發送到接收端
* 4.釋放資源
*/
public class UDPSend {
public static void main(String[] args) throws IOException {
//1.創建DatagramPacket對象,封裝要傳輸的數據,封裝接收端的IP地址,封裝接收端的端口號
//封裝要傳輸的數據
byte[] bytes = "你好UDP".getBytes();
//封裝接收端的IP地址
InetAddress inet = InetAddress.getByName("127.0.0.1");//127.0.0.1本地(自己的電腦)IP
//封裝接收端的端口號
int port = 8888;
DatagramPacket dp = new DatagramPacket(bytes, bytes.length, inet, port);
//2.創建DatagramSocket對象,用來發送數據報包
DatagramSocket ds = new DatagramSocket();
//3.調用DatagramSocket對象中的send方法,把數據報包發送到接收端
ds.send(dp);
//4.釋放資源
ds.close();
}
}
/*
* TCP文件上傳的客戶端:讀取本地文件,上傳到服務器
*
* 操作流程:
* 1.創建客戶端Socket對象,綁定服務器的IP地址和端口號
* 2.創建本地字節輸入對象,並且綁定數據源
* 3.通過Socket對象中的方法getOutputStream,獲取Socket輸出流對象
* 4.使用本地字節輸入對象,讀取硬盤上要上傳的文件
* 5.使用Socket輸出流對象把讀取到的文件,發送到服務器
* 6.通過Socket對象中的方法getIntputStream,獲取Socket輸入流對象
* 7.通過Socket輸入流對象讀取服務器回寫的數據
* 8.釋放資源(本地流,Socket)
*/
public class TCPClient {
public static void main(String[] args) throws IOException {
//1.創建客戶端Socket對象,綁定服務器的IP地址和端口號
Socket socket = new Socket("127.0.0.1", 8888);
//2.創建本地字節輸入對象,並且綁定數據源
FileInputStream fis = new FileInputStream("c:\\1.jpg");
//3.通過Socket對象中的方法getOutputStream,獲取Socket輸出流對象
OutputStream os = socket.getOutputStream();
//4.使用本地字節輸入對象,讀取硬盤上要上傳的文件
//使用數組緩衝讀取
byte[] bytes = new byte[1024];
int len = 0;
while((len = fis.read(bytes))!=-1){
//5.使用Socket輸出流對象把讀取到的文件,發送到服務器
os.write(bytes, 0, len);
}
//需要給服務寫一個上傳完數的終止符號
/*
* public void shutdownOutput()
* 禁用此套接字的輸出流。對於 TCP 套接字,任何以前寫入的數據都將被髮送,並且後跟 TCP 的正常連接終止序列。
*/
socket.shutdownOutput();
//6.通過Socket對象中的方法getIntputStream,獲取Socket輸入流對象
InputStream is = socket.getInputStream();
//7.通過Socket輸入流對象讀取服務器回寫的數據
while((len = is.read(bytes))!=-1){
//看服務器回寫的數據
System.out.println(new String(bytes,0,len));
}
//8.釋放資源(本地流,Socket)
fis.close();
socket.close();
}
}
/*
*
*TCP 文件上傳多線程版本的服務器
* 永不停歇的接收客戶端的上傳的文件
* 只要有客戶端上傳文件,就開啓一個線程,完成文件的保存
*
*/
public class TCPServer {
public static void main(String[] args) throws IOException {
// 1.創建服務器ServerSocket對象,綁定端口號
ServerSocket server = new ServerSocket(8888);
// 永不停歇的接收客戶端的上傳的文件
while (true) {
// 2.獲取客戶端Socket對象
Socket socket = server.accept();
// 只要有客戶端上傳文件,就開啓一個線程,完成文件的保存
new Thread(new Upload(socket)).start();
}
// 不用關閉
// server.close();
}
}
/*
* 文件上傳的線程
*/
public class Upload implements Runnable{
private Socket socket;
//給Socket賦值
public Upload(Socket socket) {
super();
this.socket = socket;
}
//線程任務:讀取客戶端的文件,保存到本地
@Override
public void run() {
try {
//3.創建保存上傳文件的文件夾
File file = new File("d:\\upload");
//判斷文件夾是否存在,不存在,則創建
if(!file.exists()){
file.mkdirs();
}
//4.通過Socket對象,獲取Socket輸入流對象
InputStream is = socket.getInputStream();
/*
* 爲了防止用戶上傳的文件被覆蓋,可以自定義文件的名稱
* 域名+毫秒值+隨機數
*/
String fileName = "itcast"+System.currentTimeMillis()+new Random().nextInt(999999)+".jpg";
//5.創建本地字節輸出流對象,綁定保存文件的目的地 "d:\\upload1.jpg" File.separator \\
FileOutputStream fos = new FileOutputStream(file+File.separator+fileName);
//6.使用Socket輸入流對象讀取客戶端上傳的文件
//使用數組緩衝讀取
byte[] bytes = new byte[1024];
int len = 0;
while((len = is.read(bytes))!=-1){
//7.使用本地字節輸出流對象中寫輸入的方法,把數據寫入到目的地
fos.write(bytes, 0, len);
}
//8.通過Socket對象,獲取Socket輸出流對象
//9.使用Socket輸出流對象中的方法,給客戶端回寫數據
socket.getOutputStream().write("上傳成功".getBytes());
//10.釋放資源(本地流,Socket,ServerSocket)
fos.close();
socket.close();
} catch (Exception e) {
System.out.println(e);
}
}
}