網絡編程概述
就是用來實現網絡互連的不同計算機上運行的程序間可以進行數據交換。
有人說,20世紀最偉大的發明不是計算機,而是計算機網絡。哈哈,的確是這樣,現在沒有網,簡直不能活下去。
計算機之間要進行通訊的話要以什么樣的規則進行通信呢,這就是網絡模型研究的問題,我們下來學習。
網絡模型
- OSI參考模型
- TCP/IP參考模型
OSI參考模型
應用層
表示層
會話層
傳輸層
網絡層
數據鏈路層
物理層
TCP/IP參考模型
應用層
傳輸層
網絡層
主機至網絡層
網絡通信三要素
- IP地址:InetAddress
- 網絡中設備的標識,不易記憶,可用主機名
- 端口號
- 用于標識進程的邏輯地址,不同進程的標識
- 傳輸協議
- 通訊的規則
常見協議:TCP,UDP
- 通訊的規則
IP地址
說起IP地址,我們每個人都知道自己的電腦有個IP地址,它在計算機中有什么作用呢?我們就來看一下它的具體概念
要想讓網絡中的計算機能夠互相通信,必須為每臺計算機指定一個標識號,也就是網絡中計算機的唯一標識,通過這個標識號來指定要接受數據的計算機和識別發送的計算機,在TCP/IP協議中,這個標識號就是IP地址。
那么,我們如何獲取和操作IP地址呢?java提供了一個類**InetAddress **供我們使用對IP地址的獲取和操作。
我們來獲取本機的主機名和IP地址
public class InetAddressDemo {
public static void main(String[] args) {
try {
InetAddress in = InetAddress.getLocalHost(); System.out.println(in.toString());
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
運行程序,我們就得到了本機的主機名和IP地址
那么我們想要知道別人的IP地址或主機名怎么辦呢?當然也是有方法的
public class InetAddressDemo {
public static void main(String[] args) throws UnknownHostException { InetAddress address = InetAddress.getByName("192.168.2.102");
// public String getHostName()獲取主機名,
String name = address.getHostName();
// public String getHostAddress()獲取IP地址
String ip = address.getHostAddress();
System.out.println(name + "---" + ip);
}
}
如果你和別人在一個局域網內,知道了他的主機名或者IP地址就可以獲取到另外一個。
端口號
端口號它分為兩種,一種是物理端口,另外一種是邏輯端口。
物理端口就是網卡口,我們要學的呢就是邏輯端口,它是什么呢?
- 每個網絡程序都會至少有一個邏輯端口
- 用于標識進程的邏輯地址,不同進程的標識
- 有效端口:065535,其中01024系統使用或保留端口。
TCP和UDP協議
TCP和UDP協議它們是通訊的規則,它們有什么區別呢?
TCP
建立連接,形成傳輸數據的通道
在連接中進行大數據量傳輸
通過三次握手完成連接,是可靠協議
必須建立連接,效率會稍低
UDP
將數據源和目的封裝成數據包中,不需要建立連接
每個數據包的大小在限制在64k
因無連接,是不可靠協議
不需要建立連接,速度快
一般的軟件它既有UDP,又有TCP,用TCP來保證軟件的可靠性,用UDP來保證軟件的傳輸速度快。
Socket
我們繼續看Socket,我們說的網絡編程也就是Socket編程也叫做網絡套接字。
- Socket套接字:
- 網絡上具有唯一標識的IP地址和端口號組合在一起才能構成唯一能識別的標識符套接字。
- Socket原理機制:
- 通信的兩端都有Socket。
- 網絡通信其實就是Socket間的通信。
- 數據在兩個Socket間通過IO傳輸。
UDP傳輸
我們要用UDP傳輸數據時,怎么用Socket建立連接呢?
- DatagramSocket與DatagramPacket
- 建立發送端,接收端。
- 建立數據包。
- 調用Socket的發送接收方法。
- 關閉Socket。
發送端與接收端是兩個獨立的運行程序。我們用代碼實現一個UDP傳輸數據的例子
UDP傳輸-發送端
/*
* 需求:接收指定端口發送過來的數據
*
* UDP協議發送數據:
* A:創建發送端Socket對象
* B:創建數據,并把數據打包
* C:調用Socket對象的發送方法發送數據包
* D:釋放資源
*/
public class SendDemo {
public static void main(String[] args) throws IOException {
// 創建發送端Socket對象
// DatagramSocket()
DatagramSocket ds = new DatagramSocket();
// 創建數據,并把數據打包
// DatagramPacket(byte[] buf, int length, InetAddress address, int port)
// 創建數據
byte[] bys = "UDP過來了".getBytes();
// 長度
int length = bys.length;
// IP地址對象
InetAddress address = InetAddress.getByName("192.168.2.102");
// 端口
int port = 12345;
DatagramPacket dp = new DatagramPacket(bys, length, address, port);
// 調用Socket對象的發送方法發送數據包
// public void send(DatagramPacket p)
ds.send(dp);
// 釋放資源
ds.close();
}
}
UDP傳輸-接收端
/* * UDP協議接收數據:
* A:創建接收端Socket對象
* B:創建一個數據包(接收容器)
* C:調用Socket對象的接收方法接收數據
* D:解析數據包,并顯示在控制臺
* E:釋放資源
*/
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
// 創建接收端Socket對象
// DatagramSocket(int port)
DatagramSocket ds = new DatagramSocket(12345);
// 創建一個數據包(接收容器)
// DatagramPacket(byte[] buf, int length)
byte[] bys = new byte[1024];
int length = bys.length;
DatagramPacket dp = new DatagramPacket(bys, length);
// 調用Socket對象的接收方法接收數據
// public void receive(DatagramPacket p)
ds.receive(dp); // 阻塞式
// 解析數據包,并顯示在控制臺
// 獲取對方的ip
// public InetAddress getAddress()
InetAddress address = dp.getAddress();
String ip = address.getHostAddress();
// public byte[] getData():獲取數據緩沖區
// public int getLength():獲取數據的實際長度
byte[] bys2 = dp.getData();
int len = dp.getLength();
String s = new String(bys2, 0, len);
System.out.println(ip + "傳遞的數據是:" + s);
// 釋放資源
ds.close();
}
}
我們先運行接收端的代碼,再運行發送端的代碼,這樣在接收端就會收到由發送端發過來的數據。完成了UDP傳輸
多線程UDP聊天
/*
* 通過多線程實現聊天程序,我們就要開啟兩個線程,一個接收數據,一個發送數據,這樣我就可以實現在一個窗口發送和接收數據了
*/
public class ChatRoom {
public static void main(String[] args) throws IOException { DatagramSocket dsSend = new DatagramSocket();
DatagramSocket dsReceive = new DatagramSocket(12345); SendThread st = new SendThread(dsSend);
ReceiveThread rt = new ReceiveThread(dsReceive);
Thread t1 = new Thread(st);
Thread t2 = new Thread(rt);
t1.start(); t2.start();
}
}
/* * 接收數據 */
public class ReceiveThread implements Runnable {
private DatagramSocket ds;
public ReceiveThread(DatagramSocket ds) {
this.ds = ds;
}
@Override
public void run() {
try { while (true) {
// 創建一個包裹
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length);
// 接收數據 ds.receive(dp);
// 解析數據
String ip = dp.getAddress().getHostAddress();
String s = new String(dp.getData(), 0, dp.getLength()); System.out.println("from " + ip + " data is : " + s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/* * 發送數據 */
public class SendThread implements Runnable {
private DatagramSocket ds;
public SendThread(DatagramSocket ds) {
this.ds = ds;
}
@Override
public void run() {
try {
// 封裝鍵盤錄入數據
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while ((line = br.readLine()) != null) {
if ("886".equals(line)) {
break;
}
// 創建數據并打包
byte[] bys = line.getBytes();
DatagramPacket dp = new DatagramPacket(bys, bys.length,InetAddress.getByName("192.168.2.102"), 12345);
// 發送數據
ds.send(dp);
}
// 釋放資源
ds.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
我們只需要運行聊天室ChatRoom類,就可以完成單窗口聊天了這里寫圖片描述你發送一句,他就會接收一句,是不是很有意思呢?