學(xué)習(xí)過(guò)程是看畢向東老師的視頻。
1.網(wǎng)絡(luò)模型
OSI參考模型 |
---|
應(yīng)用層 |
表示層 |
會(huì)話層 |
傳輸層 |
網(wǎng)絡(luò)層 |
數(shù)據(jù)鏈路層 |
物理層 |
面試的時(shí)候,技術(shù)總監(jiān)最后和我說(shuō)到這里時(shí),我表示一臉蒙蔽,說(shuō)不出這7層名字都是啥。
TCP/IP 參考模型 |
---|
應(yīng)用層 |
傳輸層 |
網(wǎng)絡(luò)層 |
主機(jī)至網(wǎng)絡(luò)層 |
根據(jù)我目前的了解,我是在最上層應(yīng)用層開發(fā)。
網(wǎng)絡(luò)通訊要素:
- IP地址
- 端口號(hào)
- 傳輸協(xié)議
2 TCP與UDP
- TCP(Transmission Control Protocol 傳輸控制協(xié)議)
在OSI中屬于第四層傳輸層的協(xié)議。是一種面向連接的,可靠的,基于字節(jié)流的的傳輸層協(xié)議。在因特網(wǎng)協(xié)議族(Internet protocol suite)中,TCP層是位于IP層之上,應(yīng)用層之下的中間層。
應(yīng)用層向TCP層發(fā)送用于網(wǎng)間傳輸?shù)摹⒂?位字節(jié)表示的數(shù)據(jù)流,然后TCP把數(shù)據(jù)流分區(qū)成適當(dāng)長(zhǎng)度的報(bào)文段(通常受該計(jì)算機(jī)連接的網(wǎng)絡(luò)的數(shù)據(jù)鏈路層的最大傳輸單元(MTU)的限制)。之后TCP把結(jié)果包傳給IP層,由它來(lái)通過(guò)網(wǎng)絡(luò)將包傳送給接收端實(shí)體的TCP層。TCP為了保證不發(fā)生丟包,就給每個(gè)包一個(gè)序號(hào),同時(shí)序號(hào)也保證了傳送到接收端實(shí)體的包的按序接收。然后接收端實(shí)體對(duì)已成功收到的包發(fā)回一個(gè)相應(yīng)的確認(rèn)(ACK);如果發(fā)送端實(shí)體在合理的往返時(shí)延(RTT)內(nèi)未收到確認(rèn),那么對(duì)應(yīng)的數(shù)據(jù)包就被假設(shè)為已丟失將會(huì)被進(jìn)行重傳。TCP用一個(gè)校驗(yàn)和函數(shù)來(lái)檢驗(yàn)數(shù)據(jù)是否有錯(cuò)誤;在發(fā)送和接收時(shí)都要計(jì)算校驗(yàn)和。
TCP三次握手的過(guò)程如下:
- 客戶端發(fā)送SYN(SEQ=x)報(bào)文給服務(wù)器端,進(jìn)入SYN_SEND狀態(tài)。
- 服務(wù)器端收到SYN報(bào)文,回應(yīng)一個(gè)SYN(SEQ=y)ACK(ACK=x+1)報(bào)文,進(jìn)入SYN_RECV狀態(tài)。
- 客戶端收到服務(wù)器端的SYN報(bào)文,回應(yīng)一個(gè)ACK(ACK=y+1)報(bào)文,進(jìn)入Established狀態(tài)。
- UDP(User Datagram Protocol用戶數(shù)據(jù)報(bào)協(xié)議)
同TCP協(xié)議同層,UDP也是第四層傳輸層的協(xié)議。是無(wú)連接的,不可靠的,協(xié)議。
UDP協(xié)議全稱是用戶數(shù)據(jù)報(bào)協(xié)議,在網(wǎng)絡(luò)中它與TCP協(xié)議一樣用于處理數(shù)據(jù)包,是一種無(wú)連接的協(xié)議。在OSI模型中,在第四層——傳輸層,處于IP協(xié)議的上一層。UDP有不提供數(shù)據(jù)包分組、組裝和不能對(duì)數(shù)據(jù)包進(jìn)行排序的缺點(diǎn),也就是說(shuō),當(dāng)報(bào)文發(fā)送之后,是無(wú)法得知其是否安全完整到達(dá)的。UDP用來(lái)支持那些需要在計(jì)算機(jī)之間傳輸數(shù)據(jù)的網(wǎng)絡(luò)應(yīng)用。包括網(wǎng)絡(luò)視頻會(huì)議系統(tǒng)在內(nèi)的眾多的客戶/服務(wù)器模式的網(wǎng)絡(luò)應(yīng)用都需要使用UDP協(xié)議。UDP協(xié)議從問(wèn)世至今已經(jīng)被使用了很多年,雖然其最初的光彩已經(jīng)被一些類似協(xié)議所掩蓋,但是即使是在今天UDP仍然不失為一項(xiàng)非常實(shí)用和可行的網(wǎng)絡(luò)傳輸層協(xié)議。
與所熟知的TCP(傳輸控制協(xié)議)協(xié)議一樣,UDP協(xié)議直接位于IP(網(wǎng)際協(xié)議)協(xié)議的頂層。根據(jù)OSI(開放系統(tǒng)互連)參考模型,UDP和TCP都屬于傳輸層協(xié)議。UDP協(xié)議的主要作用是將網(wǎng)絡(luò)數(shù)據(jù)流量壓縮成數(shù)據(jù)包的形式。一個(gè)典型的數(shù)據(jù)包就是一個(gè)二進(jìn)制數(shù)據(jù)的傳輸單位。每一個(gè)數(shù)據(jù)包的前8個(gè)字節(jié)用來(lái)包含報(bào)頭信息,剩余字節(jié)則用來(lái)包含具體的傳輸數(shù)據(jù)。
以上主要摘抄百度百科。
3.TCP和UDP的特點(diǎn)
TCP特點(diǎn)
- 建立連接,形成傳輸數(shù)據(jù)的通道
- 在連接中進(jìn)行大量的數(shù)據(jù)傳輸
- 三次握手,可靠
- 由于必須建立連接,效率稍低
UDP特點(diǎn)
- 將數(shù)據(jù)、源和目的封裝成數(shù)據(jù)包,不需要建立連接
- 每個(gè)數(shù)據(jù)報(bào)的大小限制在64k
- 不可靠,可能丟包
- 由于不需要建立連接,所以速度快
常見(jiàn)的使用場(chǎng)景
UDP:聊天,視頻會(huì)議
TCP:下載文件
4.Socket
網(wǎng)絡(luò)上的兩個(gè)程序通過(guò)一個(gè)雙向的通信連接實(shí)現(xiàn)數(shù)據(jù)的交換,這個(gè)連接的一端稱為一個(gè)Socket。兩個(gè)Socket間通信主通過(guò)IO。Socket進(jìn)行通信所需要的協(xié)議不只有TCP/IP,在Java中主要就是TCP/IP協(xié)議。
TCP/IP協(xié)議
Transmission ControlProtocol/InternetProtocol的簡(jiǎn)寫,中譯名為傳輸控制協(xié)議/因特網(wǎng)互聯(lián)協(xié)議,又名網(wǎng)絡(luò)通訊協(xié)議,是Internet最基本的協(xié)議、Internet國(guó)際互聯(lián)網(wǎng)絡(luò)的基礎(chǔ),由網(wǎng)絡(luò)層的IP協(xié)議和傳輸層的TCP協(xié)議組成。TCP/IP 定義了電子設(shè)備如何連入因特網(wǎng),以及數(shù)據(jù)如何在它們之間傳輸?shù)臉?biāo)準(zhǔn)。協(xié)議采用了4層的層級(jí)結(jié)構(gòu),每一層都呼叫它的下一層所提供的協(xié)議來(lái)完成自己的需求。
通俗而言:TCP負(fù)責(zé)發(fā)現(xiàn)傳輸?shù)膯?wèn)題,一有問(wèn)題就發(fā)出信號(hào),要求重新傳輸,直到所有數(shù)據(jù)安全正確地傳輸?shù)侥康牡亍6鳬P是給因特網(wǎng)的每一臺(tái)聯(lián)網(wǎng)設(shè)備規(guī)定一個(gè)地址。
TCP通信需要Socket
和ServerSocket
兩個(gè)類。
客戶端對(duì)應(yīng)Socket
,服務(wù)端對(duì)應(yīng)ServerSocket
。
TCP建立兩個(gè)Socket的過(guò)程:
當(dāng)客戶端有Socket試圖連接服務(wù)端某個(gè)目標(biāo)端口時(shí),監(jiān)聽(tīng)這個(gè)服務(wù)端目標(biāo)端口的ServerSocket就會(huì)接受(accept)這個(gè)客戶端的Socket請(qǐng)求,ServerSocket并在服務(wù)端建立一個(gè)Socket來(lái)與客戶端進(jìn)行通信。這時(shí),客戶端和服務(wù)端便各有了一個(gè)Socket。
UDP客戶端和服務(wù)端的兩個(gè)Socket進(jìn)行通信,需要DatagramSocket
和DatagramPacket
這兩個(gè)封裝好的類。
DatagramSocket
This class represents a socket for sending and receiving datagram packets.
DatagramPacket
This class represents a datagram packet.
感覺(jué)英文反而容易理解一些。
DatagramPacket
:把數(shù)據(jù)進(jìn)行封裝的數(shù)據(jù)報(bào)包。作用是用來(lái)實(shí)現(xiàn)無(wú)連接的包投遞服務(wù)。
DatagramSocket
:負(fù)責(zé)發(fā)送和接受數(shù)據(jù)報(bào)包。
5.UDP簡(jiǎn)單實(shí)例
客戶端向服務(wù)端發(fā)送Hello World!
客戶端代碼:
public class UdpSend {
public static void main(String[] args) {
String info = "Hello World";
int port = 10888;
boolean b = sendMessage(info, port);
if (b) {
System.out.println("ok!!!");
}
}
private static boolean sendMessage(String info, int port) {
try {
// 1 創(chuàng)建DatagragmSocket對(duì)象
int me = 10887;
DatagramSocket ds = new DatagramSocket(me);
// 2 創(chuàng)建DatagramPacket對(duì)象
byte[] buf = info.getBytes();// byte[]
InetAddress address = InetAddress.getByName("192.168.0.103");// IP
DatagramPacket dp = new DatagramPacket(buf, buf.length, address, port);
// 3 發(fā)送數(shù)據(jù)
ds.send(dp);
// 4 關(guān)閉連接
ds.close();
return true;
} catch (Exception e) {
return false;
}
}
}
在客戶端代碼中,客戶端端口號(hào)為10887,服務(wù)端端口號(hào)為10888.
DatagramSocket
構(gòu)造方法中的端口號(hào)為自己的端口號(hào)10887。
DatagramPacket
構(gòu)造方法中也需要一個(gè)端口號(hào),但這個(gè)端口號(hào)為服務(wù)端,接收DatagramPacket
這個(gè)數(shù)據(jù)報(bào)包的DatagramSocket
的端口號(hào)10888。
服務(wù)端代碼:
public class UdpReceiver {
public static void main(String[] args) {
int port = 10888;
receString(port);
}
private static void receString(int port) {
try {
// 1 創(chuàng)建DatagramSocket對(duì)象 確定端口
DatagramSocket ds = new DatagramSocket(port);
// 2 創(chuàng)建DatagramPacket
byte[] buf = new byte[1024 * 8];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
// 3 將接收到的數(shù)據(jù)放入DatagramPacket中
ds.receive(dp);
// 4 利用DatagramPacket的方法拿到具體的數(shù)據(jù)
String ip = dp.getAddress().getHostAddress();
int p = dp.getPort();
19行: String info = new String(dp.getData(), 0, dp.getLength());
System.out.println(ip + "\n" + info + "\n" + p);
// 關(guān)閉連接
ds.close();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
需要注意的是19行中,拿String數(shù)據(jù)時(shí),通過(guò)dp.getLength()
這個(gè)方法,根據(jù)DatagramPacket
中數(shù)據(jù)的時(shí)機(jī)大小來(lái)確定。因?yàn)槎x的buf
的大小為1024 * 8
。
還有就是記得關(guān)閉連接。
6.TCP簡(jiǎn)單實(shí)例
客戶端代碼:
public class TcpClient {
public static void main(String[] args) {
String info = "Hello world!";
boolean b = sendMessage(info);
if (b) {
System.out.println("ok");
}
}
private static boolean sendMessage(String info) {
int port = 10902;
try {
InetAddress address = InetAddress.getByName("192.168.0.103");
// 1 建立Socket
Socket socket = new Socket(address, port);
// 2 拿到輸出流
OutputStream outputStream = socket.getOutputStream();
// 3 寫入數(shù)據(jù)
outputStream.write(info.getBytes());
// 4 關(guān)閉Socket
socket.close();
return true;
} catch (Exception e) {
return false;
}
}
}
服務(wù)端代碼:
public class TcpServer {
public static void main(String[] args) {
receInfo();
}
private static void receInfo() {
try {
// 1 建立ServerSocket
ServerSocket serverSocket = new ServerSocket(10902);
// 2 通過(guò)accept()拿到Socket
Socket socket = serverSocket.accept();
// 打印IP
System.out.println(socket.getInetAddress().getHostAddress());
// 3 通過(guò)Socket拿到輸入流
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[1024];
int len;
// 4 讀取數(shù)據(jù)
while ((len = inputStream.read(buf)) != -1) {
String info = new String(buf, 0, len);
System.out.println(info);
}
// 5 關(guān)閉Socket和ServerSocket
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客戶端Socket
和服務(wù)端ServerSocket
的端口號(hào)為一個(gè)。ServerSocket
就是通過(guò)端口號(hào)和客戶端的Socket
通過(guò)accept()
建立聯(lián)系。
7.最后
UDP通信依賴DatagramSocket
和DatagramPacket
。
TCP通信依賴Socket
和ServerSocket
。
Java Socket網(wǎng)絡(luò)編程最基礎(chǔ)的部分有了一點(diǎn)了解,還有很多東西就需要以后繼續(xù)深入學(xué)習(xí)。有錯(cuò)誤希望可以指出。: )
共勉。