zoukankan      html  css  js  c++  java
  • 基于Socket的网络数据传输测试(Java+Android+腾讯云)

    零、前言

    1.本文不是大讲特讲UDP和TCP的区别,或者其流程,只是基于此作些小测试
    2.UDP分为[发送端]与[接收端],[发送方]将数据打包发出去后不关心是否被接收
    [发送方]需要持有[接收端]的ip地址及端口,[接收端]可以在相应端口监听,否则称为[丢包]
    3.TCP分为[服务端]与[客户端],[服务端]提供服务,如果未开启,[客户端]访问将报错
    [客户端]需要持有[服务端]的ip地址及端口,[接收端]必须在相应端口监听,否则报错
    项目源码:Github:https://github.com/toly1994328/SocketDemo


    上篇:UDP测试----面相无连接

    1.完成两个终端(计算机、手机)之间的信息数据传输
    2.java控制台、java的GUI、Android界面都只是作为java的一种展现形式,任何一方都可以作为发送端或接收端
    3.场景一:java控制台与控制台间的消息传输
    4.场景二:java控制台与GUI间的消息传输
    5.场景三:java控制台与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

    一、java控制台与控制台测试

    1:updSocket服务端:数据发送方

    思路

     * 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:客户端:数据接收方

    思路

    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

    二、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+"
    ");
                    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

    三、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

    二、文件上传

    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----看到这里,我在此感谢你的喜欢与支持

  • 相关阅读:
    【转】前端防止 JS 调试技巧
    反爬虫 js怎样判断是真实点击事件还是模拟点击事件?
    js 前端 滑动验证
    【转】pyspider运行卡死在result_worker starting 的解决办法
    【转】pyspider all命令报错如下:ImportError: cannot import name 'DispatcherMiddleware' from 'werkzeug.wsgi'
    【转】pyspider中async关键字问题
    【转】Windows python3.7 下安装运行pyspider
    如何修改11g RAC集群名称
    Exadata健康检查工具EXAchk
    XD刷机中执行reclaimdisks.sh的作用
  • 原文地址:https://www.cnblogs.com/toly-top/p/9781851.html
Copyright © 2011-2022 走看看