一.概念
網(wǎng)絡(luò)分層:
應(yīng)用層:HTTP/WebSocket(Html)温算、DNS怜校、FTP、SMTP/POP3/IMAP注竿、XMPP/MQTT茄茁、TELNET/SSH
傳輸層:TCP/UDP(Socket)、DCCP巩割、RTP裙顽、PPTP
網(wǎng)絡(luò)層:IP、ICMP(ping)喂分、IGMP锦庸、RIP
鏈路層: IP數(shù)據(jù)報(bào)封裝成合適在物理層傳輸?shù)膸袷? 物理層: 實(shí)現(xiàn)bit流在結(jié)點(diǎn)間傳輸,既與鏈路有關(guān),也與傳輸介質(zhì)有關(guān)
鏈路層協(xié)議MTU(最大傳輸單元):
FDDI協(xié)議:4352字節(jié)
以太網(wǎng)Ethernet協(xié)議:1500字節(jié)
PPPoE(ADSL)協(xié)議:1492字節(jié)
X.25協(xié)議(Dial Up/Modem):576字節(jié)
Point-to-Point:4470字節(jié)
二.區(qū)別
若傳輸層數(shù)據(jù)大于MTU,則IP協(xié)議會(huì)分包,IP頭部序號(hào)使數(shù)據(jù)包按序重組机蔗!
TCP協(xié)議可完成數(shù)據(jù)分包與重組,數(shù)據(jù)包在576字節(jié)以內(nèi),無需IP協(xié)議分包蒲祈!
若在局域網(wǎng)(以太網(wǎng)協(xié)議),UDP數(shù)據(jù)包最好控制在1472字節(jié)以內(nèi)!
若在互聯(lián)網(wǎng),存在不同鏈路層協(xié)議,最小MTU是576字節(jié),UDP數(shù)據(jù)包最好控制在576以內(nèi)萝嘁!
TCP協(xié)議: 發(fā)送數(shù)據(jù)之前,三次握手建立連接,傳輸完成,四次揮手?jǐn)嚅_連接;
實(shí)現(xiàn)數(shù)據(jù)分包與按序重組
低效率,但接收數(shù)據(jù)準(zhǔn)確
java類庫: Socket/ServerSocket
UDP協(xié)議: 直接發(fā)送數(shù)據(jù),不建任何連接,不管對(duì)方是否收到;
數(shù)據(jù)包無序列號(hào),接收端不保證順序
高效率,但接收數(shù)據(jù)包可能丟失或亂序
java類庫: DatagramSocket/DatagramPacket
與HTTP區(qū)別:
HTTP是在TCP連接的基礎(chǔ)上,增加了數(shù)據(jù)封裝格式,
還添加了限制:只能客戶端主動(dòng)請(qǐng)求,服務(wù)端不能主動(dòng)發(fā)送(推送)數(shù)據(jù),
我猜早期設(shè)計(jì)者是為了簡化瀏覽器,畢竟早期瀏覽器只用來瀏覽器而已梆掸!
然而現(xiàn)在網(wǎng)頁網(wǎng)羅一切,推送消息就必不可少,如果不斷輪詢服務(wù)器,顯然效果差!
雖然HTTP1.1默認(rèn)長連接(即不斷開TCP連接),但是服務(wù)器想主動(dòng)推送,還是不行!
因?yàn)閷?shí)現(xiàn)HTTP協(xié)議瀏覽器都沒有監(jiān)聽TCP端口,不可能知道服務(wù)器主動(dòng)發(fā)了請(qǐng)求牙言!
所以出現(xiàn)了變相實(shí)現(xiàn)推送:服務(wù)器收到請(qǐng)求,不響應(yīng),需要推送時(shí)才響應(yīng)瀏覽器!
此外酸钦,Html5新協(xié)議WebSocket也是為彌補(bǔ)Http缺少推送而產(chǎn)生的!
TCP則沒有限制,是雙向通信,只要知道對(duì)方ip端口,雙方就可主動(dòng)發(fā)數(shù)據(jù)(但對(duì)方須監(jiān)聽端口)
三.java使用TCP協(xié)議
// TCP客戶端
public class TCPClient{
public static void main(String args[]) throws Exception{
// 1.輸入服務(wù)端IP和端口咱枉,下載文件路徑
String ip = args[0];
int port = Integer.parseInt(args[1]);
String filePath = args[2];
Socket socket = new Socket(ip, port);
// 2.建立TCP連接卑硫,發(fā)送文件路徑
new DataOutputStream(socket.getOutputStream()).writeUTF(filePath);
// 3.接收文件名,大小蚕断,內(nèi)容
DataInputStream sin = new DataInputStream(socket.getInputStream());
FileOutputStream fou = new FileOutputStream(System.currentTimeMillis()+"_"+sin.readUTF());
long len = sin.readLong();
int pro=0;
int l;
byte[] b = new byte[1024*1024];
while ((l = sin.read(b)) != -1) {
fou.write(b,0,l);
pro += l;
System.out.println("下載大小"+String.format("%.2f",pro/1024f/1024)+"MB, "+
"進(jìn)度"+String.format("%.2f",pro*100f/len)+"%");
}
sin.close();
fou.close();
socket.close();
}
}
// TCP服務(wù)端
public class TCPServer{
public static void main(String arg[]) throws Exception{
// 1.輸入服務(wù)端監(jiān)聽端口
String port = arg[0];
ServerSocket serverSocket = new ServerSocket(Integer.parseInt(port));
while (true) {
// 2.死循環(huán)監(jiān)聽端口,等待客戶端請(qǐng)求
System.out.println("正在監(jiān)聽"+port+"端口欢伏。。亿乳。\n");
Socket socket = serverSocket.accept();
// 3.TCP連接成功硝拧,接收客戶端請(qǐng)求文件路徑
String filePath = new DataInputStream(socket.getInputStream()).readUTF();
File file = new File(filePath);
FileInputStream fin = new FileInputStream(file);
System.out.println("TCP連接成功,客戶端請(qǐng)求文件路徑"+filePath);
// 4.發(fā)送文件
DataOutputStream sou = new DataOutputStream(socket.getOutputStream());
sou.writeUTF(file.getName());
sou.writeLong(file.length());
byte[] b = new byte[1024*1024];
int l;
while ((l = fin.read(b)) != -1) {
sou.write(b, 0, l);
System.out.println("正在發(fā)送文件葛假。障陶。。");
}
System.out.println("文件發(fā)送完成\n");
fin.close();
sou.close();
socket.close();
}
}
}
四.java使用UDP協(xié)議
// UDP客戶端
public class UDPClient{
public static void main(String[] args)throws IOException{
// 1.直接發(fā)數(shù)據(jù)(不建立連接)
DatagramSocket dsocket = new DatagramSocket();
byte[] sen = "你好!我是UDP客戶端".getBytes("utf-8");
dsocket.send(new DatagramPacket(sen,sen.length,InetAddress.getByName("localhost"),9999));
System.out.println("客戶端發(fā)送");
// 2.接收數(shù)據(jù)
DatagramPacket rec = new DatagramPacket(new byte[100],100);
dsocket.receive(rec);
dsocket.close();
System.out.println("客戶端接收:" + new String(rec.getData(),0,rec.getLength()));
}
}
// UDP服務(wù)端
public class UDPServer{
public static void main(String[] args)throws IOException{
DatagramSocket dsocket = new DatagramSocket(9999);
DatagramPacket rec = new DatagramPacket(new byte[100], 100);
while (true) {
// 1.監(jiān)聽端口
System.out.println("監(jiān)聽等待...");
dsocket.receive(rec); // 線程等待, 直到接收到消息
// 2.接收數(shù)據(jù)
System.out.println("服務(wù)端接收:"+new String(rec.getData(), 0, rec.getLength()));
// 3.發(fā)送數(shù)據(jù)
byte[] sec = "你好!我是服務(wù)端".getBytes("utf-8");
dsocket.send(new DatagramPacket(sec, sec.length, rec.getAddress(), rec.getPort()));
System.out.println("服務(wù)端響應(yīng)!");
}
}
簡書: http://www.reibang.com/p/83330e36b4de
CSDN博客: http://blog.csdn.net/qq_32115439/article/details/55798783
GitHub博客:http://lioil.win/2017/02/19/TCP-UDP.html
Coding博客:http://c.lioil.win/2017/02/19/TCP-UDP.html