wifi app study:
try {
s = new DatagramSocket();
} catch (SocketException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Thread listenThread = new Thread(new Runnable() {
@Override
public void run() {
try {
DatagramSocket sock = new DatagramSocket(7001);
while (listening) {
byte[] message = new byte[1500];
DatagramPacket p = new DatagramPacket(message, message.length);
sock.receive(p);
String text = new String(message, 0, p.getLength());
serverMsgs = text;
hand.post(new Runnable() {
@Override
public void run() {
v.invalidate();
}
});
}
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
listenThread.start();
v = new View(this) { protected void onDraw(Canvas g) { float w=width, h=height; Paint wpt = new Paint(); wpt.setColor(Color.WHITE); wpt.setStyle(Style.FILL); g.drawRect(0, 0, w,h, wpt); Paint p = new Paint(); p.setColor(Color.BLACK); p.setStrokeWidth(3); float widthRange = w/2; float heightRange = h; g.drawLine(thrCenterX, 0, thrCenterX, h, p); g.drawLine(0, thrCenterY, w/2, thrCenterY, p); g.drawCircle((int)(thrCenterX + (yaw/50.0)*(widthRange/2)), (int)(h - (throttle/100.0)*heightRange), 10, p); g.drawCircle((int)(pitCenterX + (roll/50.0)*(widthRange/2)), (int)(pitCenterY - (pitch/50.0)*(heightRange/2)), 10, p); g.drawLine(pitCenterX, 0, pitCenterX, h, p); g.drawLine(w/2, pitCenterY, w, pitCenterY, p); Paint p2 = new Paint(); String disp_cmd = String.format(Locale.US,"T: %.1f Y: %.1f P: %.1f R: %.1f",throttle,yaw,pitch,roll); g.drawText(disp_cmd, 10, 10, p2); Paint p3 = new Paint(); p3.setTextSize(20); g.drawText(serverMsgs, 10, 40, p3); } }; |
public boolean onOptionsItemSelected(MenuItem item)
{
if (item.getTitle() == "PID") {
Intent intent = new Intent(this, PIDActivity.class);
startActivity(intent);
}
if (item.getTitle() == "Camera") {
Intent intent = new Intent(this, CameraActivity.class);
startActivity(intent);
}
if (item.getTitle() == "Trim") {
Intent intent = new Intent(this, TrimActivity.class);
startActivity(intent);
}
return true;
}
Java使用DatagramSocket代表UDP协议的Socket,DatagramSocket本身只是码头,不维护状态,不能产生IO流,它的唯一作用就是接收和发送数据报,Java使用DatagramPacket来代表数据报,DatagramSocket接收和发送的数据都是通过DatagramPacket对象完成的。
先看一下DatagramSocket的构造器。
DatagramSocket():创建一个DatagramSocket实例,并将该对象绑定到本机默认IP地址、本机所有可用端口中随机选择的某个端口。
DatagramSocket(int prot):创建一个DatagramSocket实例,并将该对象绑定到本机默认IP地址、指定端口。
DatagramSocket(int port, InetAddress laddr):创建一个DatagramSocket实例,并将该对象绑定到指定IP地址、指定端口。
通过上面三个构造器中的任意一个构造器即可创建一个DatagramSocket实例,通常在创建服务器时,创建指定端口的DatagramSocket实例--这样保证其他客户端可以将数据发送到该服务器。一旦得到了DatagramSocket实例之后,就可以通过如下两个方法来接收和发送数据。
receive(DatagramPacket p):从该DatagramSocket中接收数据报。
send(DatagramPacket p):以该DatagramSocket对象向外发送数据报。
当Client/Server程序使用UDP协议时,实际上并没有明显的服务器端和客户端,因为两方都需要先建立一个DatagramSocket对象,用来接收或发送数据报,然后使用DatagramPacket对象作为传输数据的载体。通常固定IP地址、固定端口的DatagramSocket对象所在的程序被称为服务器,因为该DatagramSocket可以主动接收客户端数据。
在接收数据之前,应该采用上面的第一个或第三个构造器生成一个DatagramPacket对象,给出接收数据的字节数组及其长度。然后调用DatagramSocket 的receive()方法等待数据报的到来,receive()将一直等待(该方法会阻塞调用该方法的线程),直到收到一个数据报为止。如下代码所示:
- // 创建一个接收数据的DatagramPacket对象
- DatagramPacket packet=new DatagramPacket(buf, 256);
- // 接收数据报
- socket.receive(packet);
在发送数据之前,调用第二个或第四个构造器创建DatagramPacket对象,此时的字节数组里存放了想发送的数据。除此之外,还要给出完整的目的地址,包括IP地址和端口号。发送数据是通过DatagramSocket的send()方法实现的,send()方法根据数据报的目的地址来寻径以传送数据报。如下代码所示:
- // 创建一个发送数据的DatagramPacket对象
- DatagramPacket packet = new DatagramPacket(buf, length, address, port);
- // 发送数据报
- socket.send(packet);
使用DatagramPacket接收数据时,会感觉DatagramPacket设计得过于烦琐。开发者只关心该DatagramPacket能放多少数据,而DatagramPacket是否采用字节数组来存储数据完全不想关心。但Java要求创建接收数据用的DatagramPacket时,必须传入一个空的字节数组,该数组的长度决定了该DatagramPacket能放多少数据,这实际上暴露了DatagramPacket的实现细节。接着DatagramPacket又提供了一个getData()方法,该方法又可以返回Datagram Packet对象里封装的字节数组,该方法更显得有些多余--如果程序需要获取DatagramPacket里封装的字节数组,直接访问传给 DatagramPacket构造器的字节数组实参即可,无须调用该方法。
当服务器端(也可以是客户端)接收到一个DatagramPacket对象后,如果想向该数据报的发送者"反馈"一些信息,但由于UDP协议是面向非连接的,所以接收者并不知道每个数据报由谁发送过来,但程序可以调用DatagramPacket的如下3个方法来获取发送者的IP地址和端口。
InetAddress getAddress():当程序准备发送此数据报时,该方法返回此数据报的目标机器的IP地址;当程序刚接收到一个数据报时,该方法返回该数据报的发送主机的IP地址。
int getPort():当程序准备发送此数据报时,该方法返回此数据报的目标机器的端口;当程序刚接收到一个数据报时,该方法返回该数据报的发送主机的端口。
SocketAddress getSocketAddress():当程序准备发送此数据报时,该方法返回此数据报的目标SocketAddress;当程序刚接收到一个数据报时,该方法返回该数据报的发送主机的SocketAddress。
- public class UdpServer
- {
- public static final int PORT = 30000;
- // 定义每个数据报的最大大小为4KB
- private static final int DATA_LEN = 4096;
- // 定义接收网络数据的字节数组
- byte[] inBuff = new byte[DATA_LEN];
- // 以指定字节数组创建准备接收数据的DatagramPacket对象
- private DatagramPacket inPacket =
- new DatagramPacket(inBuff , inBuff.length);
- // 定义一个用于发送的DatagramPacket对象
- private DatagramPacket outPacket;
- // 定义一个字符串数组,服务器端发送该数组的元素
- String[] books = new String[]
- {
- "疯狂Java讲义",
- "轻量级Java EE企业应用实战",
- "疯狂Android讲义",
- "疯狂Ajax讲义"
- };
- public void init()throws IOException
- {
- try(
- // 创建DatagramSocket对象
- DatagramSocket socket = new DatagramSocket(PORT))
- {
- // 采用循环接收数据
- for (int i = 0; i < 1000 ; i++ )
- {
- // 读取Socket中的数据,读到的数据放入inPacket封装的数组里
- socket.receive(inPacket);
- // 判断inPacket.getData()和inBuff是否是同一个数组
- System.out.println(inBuff == inPacket.getData());
- // 将接收到的内容转换成字符串后输出
- System.out.println(new String(inBuff
- , 0 , inPacket.getLength()));
- // 从字符串数组中取出一个元素作为发送数据
- byte[] sendData = books[i % 4].getBytes();
- // 以指定的字节数组作为发送数据,以刚接收到的DatagramPacket的
- // 源SocketAddress作为目标SocketAddress创建DatagramPacket
- outPacket = new DatagramPacket(sendData
- , sendData.length , inPacket.getSocketAddress());
- // 发送数据
- socket.send(outPacket);
- }
- }
- }
- public static void main(String[] args)
- throws IOException
- {
- new UdpServer().init();
- }
- }
客户端程序代码也与此类似,客户端采用循环不断地读取用户键盘输入,每当读取到用户输入的内容后就将该内容封装成DatagramPacket数据报,再将该数据报发送出去;接着把DatagramSocket中的数据读入接收用的DatagramPacket中(实际上是读入该DatagramPacket所封装的字节数组中)。客户端程序代码如下。
17.4.2 使用DatagramSocket发送、接收数据(3)
程序清单:codes\17\17.4\UdpClient.java
- public class UdpClient
- {
- // 定义发送数据报的目的地
- public static final int DEST_PORT = 30000;
- public static final String DEST_IP = "127.0.0.1";
- // 定义每个数据报的最大大小为4KB
- private static final int DATA_LEN = 4096;
- // 定义接收网络数据的字节数组
- byte[] inBuff = new byte[DATA_LEN];
- // 以指定的字节数组创建准备接收数据的DatagramPacket对象
- private DatagramPacket inPacket =
- new DatagramPacket(inBuff , inBuff.length);
- // 定义一个用于发送的DatagramPacket对象
- private DatagramPacket outPacket = null;
- public void init()throws IOException
- {
- try(
- // 创建一个客户端DatagramSocket,使用随机端口
- DatagramSocket socket = new DatagramSocket())
- {
- // 初始化发送用的DatagramSocket,它包含一个长度为0的字节数组
- outPacket = new DatagramPacket(new byte[0] , 0
- , InetAddress.getByName(DEST_IP) , DEST_PORT);
- // 创建键盘输入流
- Scanner scan = new Scanner(System.in);
- // 不断地读取键盘输入
- while(scan.hasNextLine())
- {
- // 将键盘输入的一行字符串转换成字节数组
- byte[] buff = scan.nextLine().getBytes();
- // 设置发送用的DatagramPacket中的字节数据
- outPacket.setData(buff);
- // 发送数据报
- socket.send(outPacket);
- // 读取Socket中的数据,读到的数据放在inPacket所封装的字节数组中
- socket.receive(inPacket);
- System.out.println(new String(inBuff , 0
- , inPacket.getLength()));
- }
- }
- }
- public static void main(String[] args)
- throws IOException
- {
- new UdpClient().init();
- }
- }
沒有留言:
張貼留言