面向UDP的Android——PC双向通信(三):在Android客户端和PC服务器端之间传输自定义对象

本文介绍如何在Android客户端与Java服务器端之间利用UDP进行自定义对象(ticket类)的双向通信。通过制定协议,将ticket对象转换为byte数组进行传输,服务器端接收到后生成订单信息并回传。在Android端,使用单例模式解决不同界面间socket共享问题,以避免端口占用导致的错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Android客户端和PC服务器端间传输自定义对象

导语

之前我们实现了Android客户端和PC服务器端之间的双向通信:
面向UDP的Android——PC双向通信(二):实现Android客户端和PC服务器端的双向通信。但仅仅是传输文本消息。接下来我们想要制定一个协议,来传输我们自定义类的对象。

这里我们考虑模拟订票系统,Android客户端向服务器端提交一个ticket对象,服务器端负责生成一些其他信息,再回传给Android端,实现一个订单的确认。

自定义ticket类

public class Ticket {
   
   
	private String name;      //购票者姓名
	private String ID;           //ID
	private String SN;          //序列号
	private String StartStation;//起始站
	private String EndStation;//终点站
	private int Type;       //车票类型
	private String Date;       //出发日期
	private String TrainNumber;      //车次
	private String StartTime; //起始时刻
	private String duration;   //时长
	private int vehicle;          //车厢
	private int seat;              //座位号
	private double price;             //票价
	//getter、setter方法
	... ...
}

Java服务器端

服务器端在之前的代码基础上,增加了ticket对象转换为byte数组、byte数组转换为ticket对象的方法。
转换的依据就是我们所制定的协议。

我们暂定的协议如下:
从客户端接收的、即将被转换为ticket对象的byte数组的格式如下:

//属性:	姓名、ID、序列号、起始站、终点站、车票类型、出发日期、车次 	 | 总
//长度:	6   |6   |8   	|8		|8		|4  	  |6	  |6	|	52
	
	/**
	 * byte数组转换为Ticket对象
	 * @param data
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public Ticket BytesToTicket(byte[] data) throws UnsupportedEncodingException{
   
   
		Ticket t = new Ticket();
		t.setName(BytesToString(subBytes(data,0,6)));
		t.setID(BytesToString(subBytes(data,6,6)));
		t.setSN(BytesToString(subBytes(data,12,8)));
		t.setStartStation(BytesToString(subBytes(data,20,8)));
		t.setEndStation(BytesToString(subBytes(data,28,8)));
		t.setType(BytesToInt(subBytes(data,36,4)));
		t.setDate(BytesToString(subBytes(data,40,6)));
		t.setTrainNumber(BytesToString(subBytes(data,46,6)));
		System.out.println(t.toString());
		return t;
	}

在接收到的ticket对象基础上,服务器生成起始时刻、时长、票价,分配车厢、座位号,再转换为byte数组:

//属性:	姓名、ID、序列号、起始站、终点站、车票类型、出发日期、车次 、起始时刻、时长、车厢、座位号、票价		|总
//长度:	6   |6   |8   	|8		|8		|4		|6	  	|6		|4		|4		|4    |4    |8    	|76

	
	/**
	 * 把ticket对象转换为要发送的byte数组
	 * @param t
	 * @return
	 * @throws Exception 
	 */
	public byte[] TicketToBytes(Ticket t) throws Exception{
   
   
		byte[] data=new byte[76];
		addBytes(StringToBytes(t.getName(),6),data,0,6);
		addBytes(StringToBytes(t.getID(),6),data,6,6);
		addBytes(StringToBytes(t.getSN(),8),data,12,8);
		addBytes(StringToBytes(t.getStartStation(),8),data,20,8);
		addBytes(StringToBytes(t.getEndStation(),8),data,28,8);
		addBytes(IntToBytes(t.getType()),data,36,4);
		addBytes(StringToBytes(t.getDate(),6),data,40,6);
		addBytes(StringToBytes(t.getTrainNumber(),6),data,46,6);
		addBytes(StringToBytes(t.getStartTime(),4),data,52,4);
		addBytes(StringToBytes(t.getDuration(),4),data,56,4);
		addBytes(IntToBytes(t.getVehicle()),data,60,4);
		addBytes(IntToBytes(t.getSeat()),data,64,4);
		addBytes(DoubleToBytes(t.getPrice()),data,68,8);
		return data;
	}

再增加一些基础数据类型之间的转换就可以了,服务器端没有遇到什么问题。

Android客户端

在Android端,ticket对象和byte数组之间的相互转换恰好与Java端相反,难度不大,这里不加赘述。

但是我们遇到了其他的问题。

之前实现双向通信仅仅是在MainActivity中进行消息收发。
而如今我们写了两个界面,在第一个界面MainActivity中填写购票信息,并点击提交,跳转第二个界面ReceiveActivity等待确认购票成功的信息。如果想要再次提交新的购票信息,则需要返回第一个界面填写购票信息。

但是重新创建第二个界面会重复执行代码:

receivesocket = new DatagramSocket(9999);

肯定会报错,因为之前的socket连接没有关闭,端口9999被占用。

如何解决socket在不同界面(前后创建ReceiveActivity的代码虽然相同,但实际上是不同的两个界面)之间共享的问题呢?

我们采用单例模式,即使用静态socket对象,这样DatagramSocket在该应用程序中只有一个实例。

在MainActivity中增加代码:

//静态变量
public static DatagramSocket receivesocket=null;
//静态方法
public static DatagramSocket getsocket() throws Exception {
   
   
        if(receivesocket==null){
   
   
        	receivesocket= new DatagramSocket(9999);
        }
        return  receivesocket;
    }

并在ReceiveActivity中更改代码:

receivesocket = MainActivity.getsocket();

至此,我们可以实现一个或多个客户端的购票提交申请,以及接收来自服务器端对应的确认购票成功的消息。但是丢包仍然是比较常见。

示例代码

服务器端代码

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;

public class UDPServer {
   
   
	public JFrame frame;
	public JLabel IPShow;
	public JLabel PortShow;
	public JTextArea MsgReceive;
	public JTextArea MsgSend;
	public JButton SendBtn
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值