基於Socket的網絡數據傳輸測試(Java+Android+騰訊雲)

零、前言

1.本文不是大講特講UDP和TCP的區別,或者其流程,只是基於此做些小測試
2.UDP分爲[發送端]與[接收端],[發送方]將數據打包發出去後不關心是否被接收
[發送方]須要持有[接收端]的ip地址及端口,[接收端]能夠在相應端口監聽,不然稱爲[丟包]
3.TCP分爲[服務端]與[客戶端],[服務端]提供服務,若是未開啓,[客戶端]訪問將報錯
[客戶端]須要持有[服務端]的ip地址及端口,[接收端]必須在相應端口監聽,不然報錯
項目源碼:Github:https://github.com/toly1994328/SocketDemojava


上篇:UDP測試----面相無鏈接

1.完成兩個終端(計算機、手機)之間的信息數據傳輸
2.java控制檯、java的GUI、Android界面都只是做爲java的一種展示形式,任何一方均可以做爲發送端或接收端
3.場景一:java控制檯與控制檯間的消息傳輸
4.場景二:java控制檯與GUI間的消息傳輸
5.場景三:java控制檯與Android的消息傳輸android

1.java控制檯與控制檯測試
9414344-170a8113ae659c4f.png
udp發送與接收消息_控制檯.png
2.java的GUI測試
9414344-06309a11e6493df0.png
udp發送與接收消息_GUI.png
3.java控制檯與安卓測試
9414344-03ef3b9b1c856274.png
udp發送與接收消息android.png

1、java控制檯與控制檯測試

1:updSocket服務端:數據發送方

思路git

* 1---經過DatagramSocket建立對象:端口8081(此端口隨意)
 * 2---使用DatagramPacket對象打包數據
 * 3---使用DatagramSocket對象發送數據包(字節數組,發送長度,ip,端口)
 * 4---關閉DatagramSocket對象
public class UDPSender {
    public static void main(String[] args) {
        System.out.println("這是發送端");
        try {
            //1: 經過DatagramSocket對象建立updSocket服務:端口8081(此端口隨意)
            DatagramSocket datagramSocket = new DatagramSocket(8081);
            //2: 使用DatagramPacket對象打包數據
            byte[] buf = "土豆土豆,我是地瓜".getBytes();
            DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.56.1"), 8080);
            //3:使用DatagramSocket對象發送數據包(字節數組,發送長度,ip,端口)
            datagramSocket.send(dp);
            //4: 關閉DatagramSocket對象
            datagramSocket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
2:客戶端:數據接收方

思路github

1---定義udpSocket服務。一般會監聽一個端口。(給網絡應用定義數字標識--便於該應用程序處理傳來數據過來)
2---定義一個數據包,由於要存儲接收到的字節數據(數據包對象中有更多功能能夠提取字節數據中的不一樣數據信息)
3---經過socket服務的receive方法將收到的數據存入已定義好的數據包中。
4---經過數據包對象的特有功能。將這些不一樣的數據取出。打印在控制檯上。
5---關閉資源。
public class UDPReceiver {
    public static void main(String[] args) throws Exception {
        System.out.println("這是接收端");
        //1:建立DatagramSocket對象,必須監聽一個端口。
        DatagramSocket ds = new DatagramSocket(8080);
        while (true) {
            //2:建立一個DatagramPacket對象,存儲接收到的字節數據
            DatagramPacket dp = new DatagramPacket(new byte[1024], 1024);
            //3:經過服務的receive方法將收到數據存入數據包中。
            ds.receive(dp);//阻塞式方法。
            //4:經過DatagramPacket對象獲取發送端傳來的數據
            String data = new String(dp.getData(), 0, dp.getLength());
            String ip = dp.getAddress().getHostAddress();
            int port = dp.getPort();
            System.out.println("來自" + ip + ":" + port + ":" + data);
        }
        //5:關閉DatagramSocket對象。
        //ds.close();
    }
}

1.先打開客戶端,而後程序因爲ds.receive(dp);會進入等待
2.打開服務端後,客戶端會接收到服務端數據
3.若是客戶端在其餘的電腦上,對應好IP和端口,也能夠打印到其餘電腦上編程

9414344-170a8113ae659c4f.png
udp發送與接收消息_控制檯.png

2、java的GUI測試

控件是經過Idea拖拽的
主要邏輯是不變的,只是在按鈕點擊時進行數據的發送文本框中的字符串,關閉窗口時關閉服務數組

1:GUI實現發送端
public class UDPSender {
    private JPanel mPanel1;
    private JButton mButton1;
    private JTextField mMsg;
    private DatagramSocket mDatagramSocket;

    public UDPSender() {
        mDatagramSocket = null;
        try {
            //1: 經過DatagramSocket建立對象:端口8081(此端口隨意)
            mDatagramSocket = new DatagramSocket(8081);
        } catch (Exception e) {
            e.printStackTrace();
        }

        mButton1.addActionListener(e -> {
            //2: 使用DatagramPacket對象打包數據
            byte[] buf = mMsg.getText().getBytes();
            DatagramPacket dp = null;
            try {
                dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.56.1"), 8080);
                //3: 使用DatagramSocket對象發送數據包(字節數組,發送長度,ip,端口)
                mDatagramSocket.send(dp);
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        });
    }

    public void close() {
        //4: 關閉DatagramSocket對象
        mDatagramSocket.close();
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("發送端");
        frame.setSize(400, 400);
        frame.setLocation(300, 200);

        UDPSender UDPSender = new UDPSender();
        frame.setContentPane(UDPSender.mPanel1);
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                UDPSender.close();
            }
        });

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}
2:GUI實現接收端
public class UDPReceiver {
    private JPanel mPanel1;
    private JTextArea mTextArea1;
    
    public static void main(String[] args) {
        JFrame frame = new JFrame("接收端");
        frame.setSize(400, 400);
        frame.setLocation(300, 200);

        UDPReceiver client = new UDPReceiver();
        frame.setContentPane(client.mPanel1);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

        StringBuilder sb = new StringBuilder();
        //1:建立DatagramSocket對象,必須監聽一個端口。
        DatagramSocket ds = null;
        try {
            ds = new DatagramSocket(8080);
            while (true) {
                //2:建立一個DatagramPacket對象,存儲接收到的字節數據
                DatagramPacket dp = new DatagramPacket(new byte[1024], 1024);
                //3:經過服務的receive方法將收到數據存入數據包中。
                ds.receive(dp);//阻塞式方法。
                //4:經過DatagramPacket對象獲取發送端傳來的數據
                String ip = dp.getAddress().getHostAddress();
                String data = new String(dp.getData(), 0, dp.getLength());
                int port = dp.getPort();
                sb.append("來自" + ip + ":" + port + ":" + data+"\n");
                client.mTextArea1.setText(sb.toString());
                System.out.println(sb.toString());
            }
            //5:關閉DatagramSocket對象。
            //ds.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
9414344-06309a11e6493df0.png
udp發送與接收消息_GUI.png

3、java控制檯與Android

在設置-->關於手機-->狀態信息 中查看手機的ip(此處使用wifi測試)
在服務端要寫對應的ip。瀏覽器

9414344-49d2841a36ae74cb.png
ip.png
1.服務端的java代碼:

鍵盤錄入做爲數據源,使用字符讀取流獲取數據,做爲發送數據服務器

public class UDPServerWithInput {
    //255,表明向該網段接收端發送 192.168.56.1~192.168.56.255 都能接收到
    public static final String IP="192.168.56.1";
    public static void main(String[] args) throws IOException {
        System.out.println("這是服務端");
        //1: 經過DatagramSocket對象建立updSocket服務:端口8081(此端口隨意)
        DatagramSocket datagramSocket = new DatagramSocket(8081);
        //準備鍵盤錄入字符讀取流
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String line = null;
        while ((line = br.readLine()) != null) {
            if ("886".equals(line)) {
                break;
            }
            byte[] buf = line.getBytes();
            //2:使用DatagramPacket對象打包數據
            DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName(IP), 8080);
            //3:使用DatagramSocket對象發送數據包(字節數組,發送長度,ip,端口)
            datagramSocket.send(dp);
        }
        //4:關閉DatagramSocket對象
        datagramSocket.close();
    }
}

2.客戶端的Android代碼微信

本示例並不須要網絡權限!
必需要在子線程接收數據,否則報異常,因此使用handler進行控件刷新網絡

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @BindView(R.id.id_tv_ip)
    TextView mIdTvIp;

    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            String obj = (String) msg.obj;
            mSb.append(obj + " ");
            mIdTvIp.setText(mSb.toString());
        }
    };
    private StringBuffer mSb;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        mSb = new StringBuffer();
        new Thread() {
            @Override
            public void run() {
                try {
                    //1:建立udp socket,創建端點。
                    DatagramSocket ds = new DatagramSocket(8080);
                    while (true) {
                        //2:定義數據包。用於存儲數據。
                        byte[] buf = new byte[1024];
                        DatagramPacket dp = new DatagramPacket(buf, buf.length);
                        //3:經過服務的receive方法將收到數據存入數據包中。
                        ds.receive(dp);//阻塞式方法。
                        //4:經過數據包的方法獲取其中的數據。
                        String data = new String(dp.getData(), 0, dp.getLength());
                        Message msg = Message.obtain();
                        msg.obj = data;
                        mHandler.sendMessage(msg);
                    }
                    //5:關閉資源
                    //ds.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}
9414344-03ef3b9b1c856274.png
udp發送與接收消息android.png

若是你想要對網絡傳輸有一點興趣,不妨親自試一下,用電腦控制手機或其餘電腦的感受還蠻不錯的。好了,就醬紫。


下篇:TCP測試:面相鏈接

在騰訊雲上開啓服務,本地計算機去鏈接,以此測試TCP鏈接,這是java服務器端最底層的原理
實現場景1:客戶端(本機)輸入一個字符串,服務端返回相應的大寫字母
實現場景2:一個客戶端(本機)上傳文件到服務器,而後經過瀏覽器訪問
實現場景3:多個客戶端(本機)同時上傳文件到服務器(併發)

前提
1.在服務器上有java環境
2.服務器上開放了測試使用的接口:本測試爲:8080端口
3.若是沒有服務器,開兩個cmd,本地也能夠測試,或者兩臺筆記本也能夠
實現場景1
9414344-d0a2240a551edcf7.png
tcp鏈接.png
實現場景2:
9414344-c7c758a57bc0ce0f.png
上傳圖片.png

1、實現場景1

一、服務端實現:

獲取socket-->經過socket獲取讀流I--> 經過socket獲取寫流O-->I讀取後轉爲大寫,用寫流O輸出

public class TransServer {
    public static void main(String[] args) {
        try {
            //1.建立ServerSocket服務對象,並指定服務端口
            ServerSocket serverSocket = new ServerSocket(8080);
            //2.經過accept方法獲取Socket對象
            Socket socket = serverSocket.accept();
            String ip = socket.getInetAddress().getHostAddress();
            System.out.println(ip + "....connected");//日誌:打印鏈接的客戶端,
            //3.得到socket對象的字節輸入流,並轉化爲字符流,包裝成BufferedReader----用於讀取客戶端數據
            BufferedReader brIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //4.得到socket對象的字節輸出流,幷包裝成PrintWriter----用於發送給客戶端數據
            PrintWriter pwOut = new PrintWriter(socket.getOutputStream(), true);
            String line = null;
            while ((line = brIn.readLine()) != null) {
                pwOut.println(line.toUpperCase());//將讀到的數據轉爲大寫,寫出到客戶端
                System.out.println(ip + ":" + line.toUpperCase());//日誌:將讀到的數據轉爲大寫,打印出來
            }
            //5.關閉資源
            serverSocket.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
2.運行服務端
編譯
javac TransServer.java -encoding utf-8
運行:此時會進入等待
java TransServer
3.客戶端的實現

創建服務-->獲取鍵盤錄入--> 將數據發給服務端-->
獲取服務端返回的大寫數據--> 結束,關資源-->

public class TransClient {
    public static void main(String[] args) {
        String ip = "193.112.165.148";
        int port = 8080;
        try {
            //1.建立Socket對象(ip,端口)
            Socket socket = new Socket(ip, port);
            //準備鍵盤錄入字符讀取流
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            //3.得到socket對象的字節輸入流,並轉化爲字符流,包裝成BufferedReader----用於讀取服務端數據
            BufferedReader brIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //4.得到socket對象的字節輸出流,幷包裝成PrintWriter----用於發送給服務端數據
            PrintWriter pwOut = new PrintWriter(socket.getOutputStream(), true);
            //注意這三個流的區別與做用:br--鍵盤錄入  brIn---讀取服務端數據  pwOut--發送給服務端數據
            String line = null;
            while ((line = br.readLine()) != null) {
                if ("over".equals(line)) {
                    break;
                }
                pwOut.println(line);//將鍵盤輸入內容發送給服務端
                System.out.println("服務端:" + brIn.readLine());//讀取服務端的數據,並打印出來
            }
            br.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

9414344-d0a2240a551edcf7.png
tcp鏈接.png

2、文件上傳

1.服務器端
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 做者:張風捷特烈
 * 時間:2018/10/8 0008:11:50
 * 郵箱:1981462002@qq.com
 * 說明:服務器端
 */
public class UpLoadFileServer {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(8080);

            while (true) {
                Socket socket = serverSocket.accept();
                String ip = socket.getInetAddress().getHostAddress();
                System.out.println(ip + "....connected");

                InputStream is = socket.getInputStream();
                String fileName = "F:\\ds.jpg";
                FileOutputStream fos = new FileOutputStream(fileName);
                int len = 0;
                byte[] buf = new byte[1024];
                while ((len = is.read(buf)) != -1) {
                    fos.write(buf, 0, len);
                }

                OutputStream os = socket.getOutputStream();
                os.write("OK".getBytes());
                fos.close();
                socket.close();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 獲取範圍隨機整數:如 rangeInt(1,9)
     *
     * @param s 前數(包括)
     * @param e 後數(包括)
     * @return 範圍隨機整數
     */
    public static int rangeInt(int s, int e) {
        int max = Math.max(s, e);
        int min = Math.min(s, e) - 1;
        return (int) (min + Math.ceil(Math.random() * (max - min)));
    }
}
2.運行服務端
編譯
javac UpLoadFileServer.java -encoding utf-8
運行:此時會進入等待
java UpLoadFileServer
3.客戶端:
public class UpLoadFileClient {
    public static void main(String[] args) {
        String ip = "193.112.165.148";
        int port = 8080;
        try {
            Socket socket = new Socket(ip, port);
            String path = "C:\\Users\\Administrator\\Desktop\\數據結構.jpg";
            FileInputStream fis = new FileInputStream(path);
            OutputStream os = socket.getOutputStream();
            byte[] buf = new byte[1024];
            int len = 0;
            while ((len = fis.read(buf)) != -1) {
                os.write(buf, 0, len);
            }
            //告訴服務端數據已寫完
            socket.shutdownOutput();

            InputStream is = socket.getInputStream();
            byte[] bufIn = new byte[1024];
            int num = is.read(bufIn);
            System.out.println(new String(bufIn, 0, num));
            fis.close();
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
9414344-c7c758a57bc0ce0f.png
上傳圖片.png

訪問:http://www.toly1994.com:8080/imgs/ds.jpg

9414344-c7a2b1fa29cc4a9e.png
結果.png

4.考慮併發:

按照上面的代碼,每次只能有一我的上傳,後者等待,顯然是不合理的,應該多我的能夠併發執行。
這裏使用多線程,每次用戶鏈接都開啓一個線程來執行帶代碼。

/**
 * 做者:張風捷特烈
 * 時間:2018/10/8 0008:11:50
 * 郵箱:1981462002@qq.com
 * 說明:併發上傳
 */
public class UpLoadFileServerCur {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(8080);
            while (true) {
                new Thread(new FileThread(serverSocket.accept())).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class FileThread implements Runnable {
    private Socket mSocket;
    public FileThread(Socket socket) {
        mSocket = socket;
    }
    @Override
    public void run() {
        String ip = mSocket.getInetAddress().getHostAddress();
        System.out.println(ip + "....connected");
        try {
            InputStream is = mSocket.getInputStream();
            String fileName = "F:\\ip" + ip + "-" + rangeInt(3000, 10000) + ".jpg";
            FileOutputStream fos = new FileOutputStream(fileName);
            int len = 0;
            byte[] buf = new byte[1024];
            while ((len = is.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }

            OutputStream os = mSocket.getOutputStream();
            os.write("上傳成功".getBytes());

            fos.close();
            mSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 獲取範圍隨機整數:如 rangeInt(1,9)
     *
     * @param s 前數(包括)
     * @param e 後數(包括)
     * @return 範圍隨機整數
     */
    public static int rangeInt(int s, int e) {
        int max = Math.max(s, e);
        int min = Math.min(s, e) - 1;
        return (int) (min + Math.ceil(Math.random() * (max - min)));
    }
}

項目源碼:Github:https://github.com/toly1994328/SocketDemo


後記:捷文規範

1.本文成長記錄及勘誤表
項目源碼 日期 備註
V0.1--無 2018-10-5 基於UDP的網絡數據傳輸測試(Java+Android)
V0.2--無 2018-10-10 將UDP和TCP合爲一篇,並優化一些表述
2.更多關於我
筆名 QQ 微信 愛好
張風捷特烈 1981462002 zdl1994328 語言
個人github 個人簡書 個人CSDN 我的網站
3.聲明

1----本文由張風捷特烈原創,轉載請註明 2----歡迎廣大編程愛好者共同交流 3----我的能力有限,若有不正之處歡迎你們批評指證,一定虛心改正 4----看到這裏,我在此感謝你的喜歡與支持

相關文章
相關標籤/搜索