基于Socket的网络数据传输测试(Java+Android+腾讯云)

mac2022-06-30  103

零、前言

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控制台与控制台测试
udp发送与接收消息_控制台.png
2.java的GUI测试
udp发送与接收消息_GUI.png
3.java控制台与安卓测试
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和端口,也可以打印到其他电脑上

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+"\n"); client.mTextArea1.setText(sb.toString()); System.out.println(sb.toString()); } //5:关闭DatagramSocket对象。 //ds.close(); } catch (Exception e) { e.printStackTrace(); } } } udp发送与接收消息_GUI.png

三、java控制台与Android

在设置-->关于手机-->状态信息 中查看手机的ip(此处使用wifi测试) 在服务端要写对应的ip。

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(); } } udp发送与接收消息android.png

如果你想要对网络传输有一点兴趣,不妨亲自试一下,用电脑控制手机或其他电脑的感觉还蛮不错的。好了,就酱紫。


下篇:TCP测试:面相连接

在腾讯云上开启服务,本地计算机去连接,以此测试TCP连接,这是java服务器端最底层的原理 实现场景1:客户端(本机)输入一个字符串,服务端返回相应的大写字母 实现场景2:一个客户端(本机)上传文件到服务器,然后通过浏览器访问 实现场景3:多个客户端(本机)同时上传文件到服务器(并发)

前提
1.在服务器上有java环境 2.服务器上开放了测试使用的接口:本测试为:8080端口 3.如果没有服务器,开两个cmd,本地也可以测试,或者两台笔记本也可以
实现场景1
tcp连接.png
实现场景2:
上传图片.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(); } } }

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(); } } } 上传图片.png

访问:http://www.toly1994.com:8080/imgs/ds.jpg

结果.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微信爱好张风捷特烈1981462002zdl1994328语言我的github我的简书我的个人网站
3.声明

1----本文由张风捷特烈原创,转载请注明 2----欢迎广大编程爱好者共同交流 3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正 4----看到这里,我在此感谢你的喜欢与支持

转载于:https://www.cnblogs.com/toly-top/p/9781851.html

相关资源:JAVA上百实例源码以及开源项目
最新回复(0)