黑馬程序員-網絡編程

——- android培訓java培訓、期待與您交流! ———-

網絡編程

UDP和TCP協議各自優缺點

1)UDP面向無連接,數據報大小有限制64K之內封包,不可靠,容易丟包,但是速度快!因此針對於數據不重要,追求速度快的常用此類協議,如聊天工具/網絡視頻會議。
2)TCP面向連接,可傳輸大樹據,經過三次握手協議,可靠,但是速度慢,消耗資源。TCP相當於打電話,UDP相當於郵局寄信。下載用的是TCP。

(一)UDP協議

  1. UDP發送數據步驟四步
    1)創建socket對象
    2)確定數據,並把數據打包
    3)發送數據
    4)關閉資源socket
public class UDPSend
{
    public static void main(String args[])
    {
        DatagramSocket ds = new DatagramSocket(8888);
        byte[] buf = "hello world!".getBytes();
        DatagramPacket dp = new DatagramPacket(buf,buf.length,"192.163.1.34","10000");
        ds.send(dp);
        ds.close();
    }
}
  1. UDP接受數據步驟
    1)創建socket對象,並指定接受端口號
    2)定義空的數據報,準備存儲接受到的數據,並利用數據報中的方法解析數據的各種信息。
    3)接收數據
    4)解析數據
    5)關閉資源
public class UDPRece
{
    public static void main(String args[])
    {
        DatagramSocket ds = new DatagramSocket(8888);
        byte[] buf = new byte[1024];//最大爲6k
        DatagramPacket dp = new DatagramPacket(buf,buf.length);
        ds.receive(dp);
        String address = dp.getAdrress().getHostAdrress();
        String data = new String(dp.getData(),0,dp.getLength());
        int port = dp.getPort();
        System.out.println(address+"..."+data+"..."+port);
        ds.close();
    }
}

192.168.1.255是個廣播地址。可以給所有機器發廣播。

示例1: 從鍵盤接收數據,可以一對一發,也可以羣發。

public class UDPSend
{
    public static void main(String args[])
    {
        DatagramSocket ds = new DatagramSocket(8888);
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String line = null;
        while((line=br.readLine())!=null)
        {
            if(line.equals("bye"))
                break;
            byte[] buf = line.getBytes();
            DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.163.1.34"),"10000");
            ds.send(dp);
        }
        ds.close();
    }
}
public class UDPRece
{
    public static void main(String args[])
    {
        DatagramSocket ds = new DatagramSocket(8888);
        while(true)
        {
            byte[] buf = new byte[1024];//最大爲6k
            DatagramPacket dp = new DatagramPacket(buf,buf.length);
            ds.receive(dp);
            String address = dp.getAdrress().getHostAdrress();
            String data = new String(dp.getData(),0,dp.getLength());
            int port = dp.getPort();
            System.out.println(address+"..."+data+"..."+port);
        }
    }
}

示例2:聊天工具,用兩個線程來寫,同樣是從鍵盤錄入數據。

class UDPSend implements Runnable
{
    private DatagramSocket ds;
    public UDPSend(DatagramSocket ds)
    {
        this.ds = ds;
    }
    public void run()
    {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String line = null;
        while((line=br.readLine())!=null)
        {
            if(line.equals("bye"))
                break;
            byte[] buf = line.getBytes();
            DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.163.1.34"),"10000");
            ds.send(dp);
        }
        ds.close();
    }
}
class UDPRece implements Runnable
{
    private DatagramSocket ds;
    public UDPRece(DatagramSocket ds)
    {
        this.ds = ds;
    }
    public void run()
    {
        while(true)
        {
            byte[] buf = new byte[1024];//最大爲6k
            DatagramPacket dp = new DatagramPacket(buf,buf.length);
            ds.receive(dp);
            String address = dp.getAdrress().getHostAdrress();
            String data = new String(dp.getData(),0,dp.getLength());
            int port = dp.getPort();
            System.out.println(address+"..."+data+"..."+port);
        }
    }
}
public class TestDemo
{
    public static void main(String args[])
    {
        DatagramSocket ds1 = new DatagramSocket();
        DatagramSocket ds2 = new DatagramSocket(10000);
        new Thread(new UDPSend(ds1));
        new Thread(new UDPRece(ds2));
    }
}

(二)TCP協議

注1:客戶端和服務器
注2:需要建立連接才能執行,需要先運行服務器,在運行客戶端

客戶端建立步驟
1. 創建socket對象,並設置連接地址和端口號
2. 獲得輸出流
3. 加載數據到輸出流中
4. 關閉客戶端

class TCPClient
{
    public static void main(String args[])
    {
        Socket sc = new Socket("192.168.1.254",10003);
        OutputStream out = ss.getOutputStream();
        out.write("hello world".getBytes());
        sc.close();
    }
}

服務器建立步驟
1. 創建server對象,設置自己的監聽端口號
2. 獲得客戶端socket對象
3. 獲得客戶端對象的輸入流,並讀取數據
4. 關閉客戶端。

class TCPServer
{
    public static void main(String args[])
    {
        ServerSocket ss = new ServerSocket(10003);
        Socket s = ss.accept();
        String ip = s.getInetAddress().getHostAddress();
        System.out.println(ip+".......");
        InputStream in = s.getInputStream();
        byte[] buf = new byte[1024];
        int len = in.read(buf);
        System.out.println(new String(buf,0,len));
        s.close();
    }
}

示例3:客戶端發送數據,服務器端接收數據,並反饋給客戶端,客戶端接收反饋並打印。

class TCPClient
{
    public static void main(String args[])
    {
        Socket s = new Socket("192.168.1.254",10001);
        OutputStream out = s.getOutputStream();
        out.write("你好,服務器!".getBytes());

        InputStream in = s.getInputStream();
        byte[] buf = new byte[1024];
        int len = 0;
        while((len=in.read(buf))!=-1)
        {
            System.out.println(new String(buf,0,len));
        }
        s.close();
    }
}
class TCPServer
{
    public static void main(String args[])
    {
        ServerSocket ss = new ServerSocket(10001);
        Socket s = ss.accept();
        String ip = s.getInetAddress().getHostAddress();
        InputStream in = s.getInputStream();
        byte[] buf = new byte[1024];
        int len = in.read(buf);
        System.out.println(new String(buf,0,len));

        OutputStream out = s.getOutputStream();
        out.write("客戶端,謝謝,已收到!!".getBytes());
        s.close();
        ss.close();
    }
}

示例4:客戶端通過鍵盤錄入文本數據,服務器將文本轉換成大寫返回給客戶端。
1)用字符緩衝流完成
2)改錯。客戶端和服務器都在莫名的等待,原因是裏面出現了阻塞式方法,這些方法沒有讀到結束標記,所以一直處於等待狀態。

class TCPClient
{
    public static void main(String args[])
    {
        Socket s = new Socket("192.168.1.254",10002);
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bufbw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        BufferedReader bufbr = new BufferedReader(new InputStreamReader(s.getInputStream()));

        String line = null;
        while((line=in.readLine())!=null)
        {
            if(line.equals("over"))
                break;
            bufbw.write(line);
            bufbw.newLine();
            bufbw.flush();

            String str = bufr.readLine();
            System.out.println("server:"+str);
        }
    }
}
class TCPServer
{
    public static void main(String args[])
    {
        ServerSocket ss = new ServerSocket(10003);
        Socket s = ss.accept();
        BufferedReader bufbr = new BufferedReader(new InputStreamReader(s.getInputStream()));
        BufferedWriter bufbw = new BufferedReader(new OutputStreamWriter(s.getOutputStream()));
        String line = null;
        while((line = bufbr.readLine())!=null)
        {
            bufbw.write(line.toUpperCase());
            bufbw.newLine();
            bufbw.flush();
        }
        s.close();
        ss.close();
    }
}

示例5:上傳文本數據。從客戶傳送硬盤文件到服務器端硬盤。文本文件。
出現問題:
1)沒有結束標記位
2)socket內部定義的結束關閉流標誌位的方法。shutdownOutput();

class TCPClient
{
    public static void main(String args[])
    {
        Socket s = new Socket("192.168.1.254",10002);
        BufferedReader in = new BufferedReader(new FileReader("c:\\client.txt"));
        PrintWriter pw = new PrintWriter(new OutputStreamWriter(s.getOutputStream()),true);
         bufbr = new BufferedReader(new InputStreamReader(s.getInputStream()));

        String line = null;
        while((line=in.readLine())!=null)
        {
            pw.println(line);
        }
        s.shutdownOutput();
        String str = bufr.readLine();
        System.out.println("server:"+str);
        in.close();
        s.close();
    }
}
class TCPServer
{
    public static void main(String args[])
    {
        ServerSocket ss = new ServerSocket(10003);
        Socket s = ss.accept();
        String ip = s.getInetAddress().getHostAddress();
        BufferedReader bufbr = new BufferedReader(new InputStreamReader(s.getInputStream()));
        BufferedWriter bw = new BufferedWriter(new FileWriter("d:\\server.txt"),true);
        String line = null;
        while((line = bufbr.readLine())!=null)
        {
            bw.write(line);
        }

        PrintWriter bufbw = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
        bufbw.write("上傳成功!!!!")

        s.close();
        ss.close();
    }
}

示例6:上傳圖片。(練習)
一個傳一個收。

class TCPClient
{
    public static void main(String args[])
    {
        Socket s = new Socket("192.168.1.254",10002);
        InputStream in = new FileInputStream("c:\\1.png");
        OutputStream out = s.getOutputStream();
        byte[] buf = new byte[1024];
        int len = 0 ; 
        while((len=in.read(buf))!=-1)
        {
            out.write(buf);
        }
        s.shutdownOutput();
        InputStream is = s.getInputStream();
        byte[] buf1 = new byte[1024];
        int len1 = is.read(buf1);
        System.out.println(new String(buf1,0,len1));
        in.close();
        s.close();
    }
}
class TCPServer
{
    public static void main(String args[])
    {
        ServerSocket ss = new ServerSocket(10003);
        Socket s = ss.accept();
        String ip = s.getInetAddress().getHostAddress();
        InputStream in = s.getInputStream();
        OutputStream ou = new FileOutputStream("d:\\2.png");
        byte[] buf = new byte[1024];
        int len = 0;
        while((len=in.read(buf))!=-1)
            ou.write(buf,0,len);
        OutputStream out = s.getOutputStream();
        out.write("上傳成功!!".getBytes());
        ou.close();
        s.close();
        ss.close();
    }
}

一個服務器,同時可以處理多個客戶端的請求。用多線程處理。
注意:需要開啓新的線程,需要保存路徑是原有文件不被覆蓋,需要傳輸特定格式和特定大小的文件。

class uploadThread
{
    private Socket socket;
    public uploadThread(Socket socket)
    {
        this.socket = socket;
    }
    public void run()
    {
        try
        {
            int count = 1;
            String ip = s.getInetAddress().getHostAddress();
            InputStream in = s.getInputStream();
            File file = new File(ip+"("+count+")"+".png");
            while(file.exist())
            {
                File file = new File(ip+"("+(count++)+")"+".png");
            }
            OutputStream ou = new FileOutputStream(file);
            byte[] buf = new byte[1024];
            int len = 0;
            while((len=in.read(buf))!=-1)
                ou.write(buf,0,len);
            OutputStream out = s.getOutputStream();
            out.write("上傳成功!!".getBytes());
            ou.close();
            s.close();
        }catch(Exception e)
        {
            throw new RuntimeException(ip+"上傳失敗!!")
        }
    }
}
class TCPServer
{
    public static void main(String args[])
    {
        ServerSocket ss = new ServerSocket(10003);
        while(true)
        {
            Socket s = ss.accept();
            new Thread(new uploadThread(s)).start();
        }
    }
}   
class TCPClient
{
    public static void main(String args[])
    {
        if(args.length!=1)
        {
            System.out.println("請選擇一個圖片格式的文件上傳");
            return;
        }
        File file = args[0];
        if(!(file.exist()&&file.isFile()))
        {
            System.out.println("該文件有問題,要麼不存在,要麼不是文件格式");
            return;
        }
        if(file.getName().endsWith(".jpg"))
        {
            System.out.println("該圖片格式不正確,請重新選擇");
            return;
        }
        if(file.length()>1024*1024*5)
        {
            System.out.println("文件過大,請重新選擇");
            return;
        }
        Socket s = new Socket("192.168.1.254",10002);
        InputStream in = new FileInputStream(file);
        OutputStream out = s.getOutputStream();
        byte[] buf = new byte[1024];
        int len = 0 ; 
        while((len=in.read(buf))!=-1)
        {
            out.write(buf);
        }
        s.shutdownOutput();
        InputStream is = s.getInputStream();
        byte[] buf1 = new byte[1024];
        int len1 = is.read(buf1);
        System.out.println(new String(buf1,0,len1));
        in.close();
        s.close();
    }
}

(三) URL

我們所常用的瀏覽器,實際上就是一個客戶端,輸入內容爲http://IP:端口號?key=alue,就相當於發送請求。
我們把http協議,IP地址,端口號和請求內容封裝到一個類中,稱爲URL。
通過URL,我們可以:
(1)獲得協議名稱,IP地址,端口號,請求內容等;
(2)可以直接獲得客戶端和服務器端的連接通道。

public class URLDemo
{
    public static void main(String args[]) throws Exception
    {
        URL url = new URL("http://192.168.1.245:8080/myweb/demo.html?name=hahha&age=39");

        System.out.println("getProtocol()"+url.getProtocol());//獲得協議
        System.out.println("getHost()"+url.getHost());//獲得IP地址
        System.out.println("getPort()"+url.getPort());//獲得端口號
        System.out.println("getPath()"+url.getPath());//獲得路徑
        System.out.println("getFile()"+url.getFile());//獲得查找內容
        System.out.println("getQuery()"+url.getQuery());//獲得查找內容

        URLConnection con = url.getConnection();//返回數據沒有頭信息。//這屬於應用層。
        InputStream in = url.openStream();//直接開流
    }
}

需要注意一點:getPort()方法,如果沒有輸入端口號,則默認爲-1;需要如下判斷:

int port = url.getPort();
        if(port==-1)
            port = 80;

以上是網絡編程的基本概念和基本思想,多做練習,多理解,多複習。

發佈了32 篇原創文章 · 獲贊 1 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章