溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

java基礎(chǔ)學(xué)習(xí)筆記:一文帶你搞懂網(wǎng)絡(luò)編程

發(fā)布時(shí)間:2020-08-11 20:34:05 來源:ITPUB博客 閱讀:136 作者:慕容扶蘇 欄目:編程語言

1. 網(wǎng)絡(luò)編程學(xué)習(xí)

1.1. 擴(kuò)展知識(shí)點(diǎn)

  1. 網(wǎng)絡(luò)協(xié)議OSI協(xié)議:網(wǎng)絡(luò)協(xié)議的劃分學(xué)習(xí)

1.2. 網(wǎng)絡(luò)協(xié)議那些事


五層協(xié)議模型
  1. 網(wǎng)絡(luò)協(xié)議按照5層劃分可以分為5層:物理層、數(shù)據(jù)鏈路層、網(wǎng)絡(luò)層,傳輸層,應(yīng)用層。每一層都有一定的協(xié)議標(biāo)準(zhǔn)定義。
  2. 物理層:物理層的協(xié)議是根據(jù)硬件傳輸數(shù)據(jù)的特性制定的協(xié)議,由于光纖,電線只能傳輸0和1二進(jìn)制數(shù)字,物理層的協(xié)議有ISO2210,IEE802,IEE8022,這一層只傳輸二進(jìn)制數(shù)據(jù)。
  3. 數(shù)據(jù)鏈路層:數(shù)據(jù)鏈路層是對(duì)電信號(hào)用來分組的,比如物理層傳來一組數(shù)據(jù)0101010101001,我們可以把它8個(gè)分成一組,16個(gè)分成一組,剛開始時(shí),各個(gè)公司都有自己的分組格式,后來國際上統(tǒng)一了標(biāo)準(zhǔn),將一組電信號(hào)稱為一個(gè)數(shù)據(jù)包,或者叫一個(gè)幀,每一個(gè)數(shù)據(jù)幀分成報(bào)頭head和數(shù)據(jù)data兩部分。head包含18個(gè)字節(jié),包含==發(fā)送者(源地址,6個(gè)字節(jié))== ,==接收者(目標(biāo)地址,6個(gè)字節(jié))== ,數(shù)據(jù)類型(6個(gè)字節(jié))data包含最短46個(gè)字節(jié),最長1500個(gè)字節(jié))
  4. 數(shù)據(jù)鏈路層是對(duì)數(shù)據(jù)進(jìn)行了簡單的封裝,用于方便傳輸數(shù)據(jù),解析數(shù)據(jù)。但是當(dāng)傳輸時(shí)有一個(gè)問題,當(dāng)處于局域網(wǎng)時(shí),也就是在同一個(gè)ip網(wǎng)關(guān)內(nèi)的不同主機(jī)可以直接傳輸數(shù)據(jù),但是如果不同網(wǎng)關(guān)的主機(jī)如何實(shí)現(xiàn)通信?==注意:在同一個(gè)網(wǎng)關(guān)內(nèi)主機(jī)之間的通信是靠廣播的方式尋找對(duì)方的。== 不在同一個(gè)網(wǎng)關(guān)內(nèi),廣播就失效了。這就引出了網(wǎng)絡(luò)層的協(xié)議。
  5. 網(wǎng)絡(luò)層:網(wǎng)絡(luò)層有IP協(xié)議,如果傳輸?shù)臄?shù)據(jù)不在同一個(gè)網(wǎng)關(guān)內(nèi),就要需要IP協(xié)議了,它是整個(gè)OSI協(xié)議的核心。只有通過配置IP才能準(zhǔn)確獲得目標(biāo)計(jì)算機(jī)的Mac地址。
  6. 應(yīng)用層:包含的協(xié)議就多了,包含HTTP協(xié)議,F(xiàn)TP協(xié)議,SMTP協(xié)議等。主要用于應(yīng)用層開發(fā)。但是HTTP協(xié)議需要TCP協(xié)議的支持。

1.3. 應(yīng)用之間通信

  1. 需要對(duì)方的ip地址,
  2. 需要對(duì)方應(yīng)用的邏輯端口號(hào),端口號(hào)要綁定應(yīng)用。

1.4. 網(wǎng)絡(luò)編程類

  1. InetAddress類
  • 該類構(gòu)造函數(shù)屬于private,不可以創(chuàng)建對(duì)象,但是里面有大量靜態(tài)方法。
  • getlocalhost()獲取主機(jī)名+ip地址。
  • getHostAddress()獲取ip地址
  • getHostName()獲取主機(jī)名,里面的參數(shù)可以是任意的,可以是www.baidu.com,將會(huì)獲取百度服務(wù)器的ip地址和主機(jī)名。

1.5. UDP協(xié)議和TCP協(xié)議

  1. UDP協(xié)議:無連接通信協(xié)議,無論對(duì)方是否在線,都可以發(fā)送,比如qq的離線發(fā)送。不過不安全,會(huì)丟數(shù)據(jù),例如廣播產(chǎn)生卡頓等。好處是傳播速度快。消耗資源小。效率高。比如手機(jī)發(fā)短信,qq發(fā)消息。UDP協(xié)議會(huì)對(duì)傳輸數(shù)據(jù)大小進(jìn)行限制,只能傳輸64kb
  2. TCP協(xié)議:面向連接的通信協(xié)議,先建立連接,才能發(fā)送數(shù)據(jù)。安全性高,速度慢。連接必須經(jīng)過三次握手。

1.6. UDP通信

  1. 實(shí)現(xiàn)UDP協(xié)議的發(fā)送端:
  • 實(shí)現(xiàn)封裝數(shù)據(jù)的類:java.net.DatagramPacket;將你的數(shù)據(jù)包裝起來
  • 實(shí)現(xiàn)數(shù)據(jù)傳輸?shù)念悾簀ava.net.DatagramSocket;將你的數(shù)據(jù)包發(fā)送出去。
  1. 實(shí)現(xiàn)步驟:
  • 創(chuàng)建DatagramPacket對(duì)象,封裝數(shù)據(jù),接收的地址和端口
  • 創(chuàng)建DatagrampSocket對(duì)象,
  • 調(diào)用DatagrampSocket的send,發(fā)送數(shù)據(jù)包。
  • 關(guān)閉資源。
  • DatagramPacket構(gòu)造方法:DatagramPacket(byte[] buf,int length,InetAddress address,int port);
  • DatagramSocket構(gòu)造方法:DatagramSocket()空參。send(DatagramPacket d);發(fā)送數(shù)據(jù)。
  • 什么是套接字:==綁定了ip地址和端口號(hào)的網(wǎng)絡(luò)對(duì)象。==
 1public static void main(String[] args) throws IOException {
 2    //創(chuàng)建數(shù)據(jù)包對(duì)象,封裝要發(fā)送的數(shù)據(jù),接收端Ip,端口號(hào)
 3    byte[] data="123udp".getBytes();
 4    //創(chuàng)建一個(gè)InetAddress對(duì)象,封裝自己的Ip地址
 5    InetAddress inetAddress =InetAddress.getByName("127.0.0.1");
 6    DatagramPacket dp =new DatagramPacket(data, data.length,inetAddress,8899);
 7    //創(chuàng)建DatagramSocket對(duì)象,
 8    DatagramSocket datagramSocket=new DatagramSocket();
 9    datagramSocket.send(dp);
10    datagramSocket.close();
11}
  1. 實(shí)現(xiàn)UDP接收端
  • 實(shí)現(xiàn)封裝數(shù)據(jù)包 java.net.DatagramPacket  將數(shù)據(jù)接收
  • 實(shí)現(xiàn)輸出傳輸 java.net.DatagramSocket  接收數(shù)據(jù)包
  1. 實(shí)現(xiàn)步驟:
  • 創(chuàng)建DatagramSocket對(duì)象,綁定端口號(hào),要與發(fā)送的端口號(hào)一致。
  • 創(chuàng)建字節(jié)數(shù)組,接收發(fā)來的數(shù)據(jù)。
  • 創(chuàng)建數(shù)據(jù)包對(duì)象DatagrampPocket接收數(shù)據(jù)。
  • 調(diào)用DatagrampSocket對(duì)象方法,receive(DatagramPacket, dp)接收數(shù)據(jù),數(shù)據(jù)放在數(shù)據(jù)包中。
  • 拆包,包含:發(fā)送端的IP,接收到的字節(jié)個(gè)數(shù),發(fā)送端的端口號(hào)。拆包時(shí),可以通過DatagramPacket獲取數(shù)據(jù)的長度getLength,然后打印該長度的數(shù)據(jù)。通過getAddress()獲取發(fā)送端的ip地址對(duì)象InetAddress,用getPort()獲取發(fā)送端的端口。發(fā)送端端口一般是操作系統(tǒng)指定的。
  • 關(guān)閉資源。
 1public static void main(String[] args) throws IOException {
 2    //創(chuàng)建數(shù)據(jù)包傳輸對(duì)象,并綁定端口號(hào)
 3    DatagramSocket ds =new DatagramSocket(8899);
 4    //創(chuàng)建字節(jié)數(shù)組
 5    byte[] buf=new byte[1024];
 6    //創(chuàng)建數(shù)據(jù)包對(duì)象傳遞字節(jié)數(shù)組
 7    DatagramPacket dp =new DatagramPacket(buf, buf.length);
 8    //調(diào)用ds的receive傳遞數(shù)組
 9    ds.receive(dp);
10    String ip =dp.getAddress().getHostAddress();
11    int port =dp.getPort();
12    int length=dp.getLength();
13    System.out.println(new String(buf,0,length)+"..."+ip+"..."+port);
14    ds.close();
15}
  1. 發(fā)送端實(shí)現(xiàn)不間斷的輸入發(fā)送數(shù)據(jù)
 1public static void main(String[] args) throws IOException {
 2      Scanner sc=new Scanner(System.in);
 3    DatagramSocket datagramSocket=new DatagramSocket();
 4    InetAddress inetAddress =InetAddress.getByName("127.0.0.1");
 5    while(true){
 6        String message=sc.nextLine();
 7        byte[] data=message.getBytes();
 8        DatagramPacket dp =new DatagramPacket(data, data.length,inetAddress,8899);
 9        datagramSocket.send(dp);
10    }
11}
  1. 實(shí)現(xiàn)永不停歇的接收端
 1public static void main(String[] args) throws IOException {
 2    //創(chuàng)建數(shù)據(jù)包傳輸對(duì)象,并綁定端口號(hào)
 3    DatagramSocket ds =new DatagramSocket(8899);
 4    //創(chuàng)建字節(jié)數(shù)組
 5    byte[] buf=new byte[1024];
 6    //創(chuàng)建數(shù)據(jù)包對(duì)象傳遞字節(jié)數(shù)組
 7    while(true){
 8        DatagramPacket dp =new DatagramPacket(buf, buf.length);
 9    //調(diào)用ds的receive傳遞數(shù)組
10        ds.receive(dp);
11           String ip =dp.getAddress().getHostAddress();
12        int port =dp.getPort();
13        int length=dp.getLength();
14            System.out.println(new String(buf,0,length)+"..."+ip+"..."+port);
15    }
16}

1.7. TCP通信

  1. TCP通信和UDP通信大致相同,分為客戶端和服務(wù)端,但是TCP通信是需要先進(jìn)行連接的,只有連接成功才能通信,不過TCP建立連接后,也就建立了IO流,可以通過IO流完成數(shù)據(jù)的傳輸。
  2. TCP客戶端程序的類 java.net.Socket:構(gòu)造方法有:Socket(String host,int port)用于傳遞服務(wù)器Ip和端口號(hào)。該構(gòu)造方法只要運(yùn)行就會(huì)和服務(wù)器連接,如果連接失敗就會(huì)拋出異常。
  3. Socket類有兩個(gè)方法,getOutputStream(),返回類型是OutputStream(),返回套接字的輸出流:作用是將數(shù)據(jù)輸出,輸出到服務(wù)器。getInputStream(),返回套接字的輸入流,返回類型是InputStream.這些方法都是從Socket中獲取的,不是new出來的。
1public static void main(String[] args) throws IOException {
2    Socket socket=new Socket("120.27.60.73", 8899);
3    OutputStream outStream=socket.getOutputStream();
4    outStream.write("789456".getBytes());
5    socket.close();
6}
  1. TCPServer端:表示服務(wù)器程序的類:java.net.ServerSocket,構(gòu)造方法有:ServerSocket(int port)傳遞端口號(hào),相當(dāng)于監(jiān)聽該端口號(hào)。
  2. 一個(gè)很重要的事情是,由于多個(gè)客戶端向服務(wù)端傳值,服務(wù)端無法辨認(rèn)是哪個(gè)客戶端發(fā)來的值,解決方法是:必須獲取客戶端的套接字對(duì)象Socket,用accept()方法獲取,返回類型是Socket
 1public static void main(String[] args) throws IOException {
 2    ServerSocket serverSocket=new ServerSocket(8899);
 3    Socket socket=serverSocket.accept();
 4    InputStream inputStream=socket.getInputStream();
 5    byte[] buf=new byte[1024];
 6    int len=inputStream.read(buf);
 7    System.out.println(new String(buf,0,len));
 8    //服務(wù)器返回?cái)?shù)據(jù)
 9    OutputStream out=socket.getOutputStream();
10    out.write("nihao".getBytes());
11    socket.close();
12    serverSocket.close();
13}

1.8. TCP通信圖片上傳服務(wù)器多線程解決方案

  1. TCP通信圖片上傳客戶端代碼
  • ==問題==:客戶端上傳圖片,客戶端可能有多個(gè)同時(shí)上傳,每次上傳圖片會(huì)傳遞一個(gè)Socket,多個(gè)上傳后會(huì)引起服務(wù)器端對(duì)Socket混亂,不知是誰的Socket對(duì)象。
  • ==解決== :多線程解決方案,每次傳來一個(gè)Socket對(duì)象,我們就為他開啟一個(gè)線程,這樣就不會(huì)造成混亂。

Socket多線程解決方案
 1public class TCPClient {
 2    public static void main(String[] args) throws IOException{
 3        Socket socket = new Socket("127.0.0.1", 8000);
 4        //獲取字節(jié)輸出流,圖片寫到服務(wù)器
 5        OutputStream out = socket.getOutputStream();
 6        //創(chuàng)建字節(jié)輸入流,讀取本機(jī)上的數(shù)據(jù)源圖片
 7        FileInputStream fis = new FileInputStream("c:\\t.jpg");
 8        //開始讀寫字節(jié)數(shù)組
 9        int len = 0 ;
10        byte[] bytes = new byte[1024];
11        while((len = fis.read(bytes))!=-1){
12            out.write(bytes, 0, len);
13        }
14        //給服務(wù)器寫終止序列
15        socket.shutdownOutput();
16
17        //獲取字節(jié)輸入流,讀取服務(wù)器的上傳成功
18        InputStream in = socket.getInputStream();
19
20        len = in.read(bytes);
21        System.out.println(new String(bytes,0,len));
22
23        fis.close();
24        socket.close();
25    }
26}
  1. 將上傳文件接收代碼放到一個(gè)線程中。這樣就保證一個(gè)線程接收一個(gè)Socket。
 1public class Upload implements Runnable{
 2
 3    private Socket socket;
 4
 5    public Upload(Socket socket){this.socket=socket;}
 6
 7    public void run() {
 8        try{
 9            //通過客戶端連接對(duì)象,獲取字節(jié)輸入流,讀取客戶端圖片
10            InputStream in = socket.getInputStream();
11            //將目的文件夾封裝到File對(duì)象
12            File upload = new File("d:\\upload");
13            if(!upload.exists())
14                upload.mkdirs();
15
16            //防止文件同名被覆蓋,從新定義文件名字
17            //規(guī)則:  域名+毫秒值+6位隨機(jī)數(shù)
18            String filename="itcast"+System.currentTimeMillis()+new Random().nextInt(999999)+".jpg";
19            //創(chuàng)建字節(jié)輸出流,將圖片寫入到目的文件夾中                         
20            FileOutputStream fos = new FileOutputStream(upload+File.separator+filename);
21            //讀寫字節(jié)數(shù)組
22            byte[] bytes = new byte[1024];
23            int len = 0 ;
24            while((len = in.read(bytes))!=-1){
25                fos.write(bytes, 0, len);
26            }
27            //通過客戶端連接對(duì)象獲取字節(jié)輸出流
28            //上傳成功寫回客戶端
29            socket.getOutputStream().write("上傳成功".getBytes());
30
31            fos.close();
32            socket.close();
33        }catch(Exception ex){
34
35        }
36    }
37
38}
  1. 服務(wù)器端,調(diào)用Thread,并將Socket作為參數(shù)傳遞給Upload類。并開啟一個(gè)新線程。并讓服務(wù)端永久的監(jiān)聽端口。
 1public class TCPThreadServer {
 2    public static void main(String[] args) throws IOException{
 3        ServerSocket server = new ServerSocket(8000);
 4        while(true){
 5            //獲取到一個(gè)客戶端,必須開啟新線程
 6            Socket socket = server.accept();
 7            new Thread( new Upload(socket) ).start();
 8        }
 9
10    }
11}

1.9. 一些技巧

  1. 公司域名+毫秒值+隨機(jī)六位數(shù),防止文件重名
1String fileName="xdclass"+System.currentTimeMillis()+new Ranadow.nextInt(999999)+".jpg";
  1. File.separator,跨系統(tǒng)生成目錄分隔符。
1File myFile = new File("C:" + File.separator + "tmp" + File.separator, "test.txt");
  1. 此外還有File.pathSeparator生成字符分號(hào);
  2. 2,3總結(jié):File類的兩個(gè)常量,一個(gè)是斜杠,一個(gè)是分號(hào)。
向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI