2016年6月21日 星期二

wifi app study



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()将一直等待(该方法会阻塞调用该方法的线程),直到收到一个数据报为止。如下代码所示:
  1. // 创建一个接收数据的DatagramPacket对象
  2. DatagramPacket packet=new DatagramPacket(buf, 256);
  3. // 接收数据报
  4. socket.receive(packet);
在发送数据之前,调用第二个或第四个构造器创建DatagramPacket对象,此时的字节数组里存放了想发送的数据。除此之外,还要给出完整的目的地址,包括IP地址和端口号。发送数据是通过DatagramSocket的send()方法实现的,send()方法根据数据报的目的地址来寻径以传送数据报。如下代码所示:
  1. // 创建一个发送数据的DatagramPacket对象
  2. DatagramPacket packet = new DatagramPacket(buf, length, address, port);
  3. // 发送数据报
  4. 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。

  1. public class UdpServer
  2. {
  3. public static final int PORT = 30000;
  4. // 定义每个数据报的最大大小为4KB
  5. private static final int DATA_LEN = 4096;
  6. // 定义接收网络数据的字节数组
  7. byte[] inBuff = new byte[DATA_LEN];
  8. // 以指定字节数组创建准备接收数据的DatagramPacket对象
  9. private DatagramPacket inPacket =
  10. new DatagramPacket(inBuff , inBuff.length);
  11. // 定义一个用于发送的DatagramPacket对象
  12. private DatagramPacket outPacket;
  13. // 定义一个字符串数组,服务器端发送该数组的元素
  14. String[] books = new String[]
  15. {
  16. "疯狂Java讲义",
  17. "轻量级Java EE企业应用实战",
  18. "疯狂Android讲义",
  19. "疯狂Ajax讲义"
  20. };
  21. public void init()throws IOException
  22. {
  23. try(
  24. // 创建DatagramSocket对象
  25. DatagramSocket socket = new DatagramSocket(PORT))
  26. {
  27. // 采用循环接收数据
  28. for (int i = 0; i < 1000 ; i++ )
  29. {
  30. // 读取Socket中的数据,读到的数据放入inPacket封装的数组里
  31. socket.receive(inPacket);
  32. // 判断inPacket.getData()和inBuff是否是同一个数组
  33. System.out.println(inBuff == inPacket.getData());
  34. // 将接收到的内容转换成字符串后输出
  35. System.out.println(new String(inBuff
  36. , 0 , inPacket.getLength()));
  37. // 从字符串数组中取出一个元素作为发送数据
  38. byte[] sendData = books[i % 4].getBytes();
  39. // 以指定的字节数组作为发送数据,以刚接收到的DatagramPacket的
  40. // 源SocketAddress作为目标SocketAddress创建DatagramPacket
  41. outPacket = new DatagramPacket(sendData
  42. , sendData.length , inPacket.getSocketAddress());
  43. // 发送数据
  44. socket.send(outPacket);
  45. }
  46. }
  47. }
  48. public static void main(String[] args)
  49. throws IOException
  50. {
  51. new UdpServer().init();
  52. }
  53. }

客户端程序代码也与此类似,客户端采用循环不断地读取用户键盘输入,每当读取到用户输入的内容后就将该内容封装成DatagramPacket数据报,再将该数据报发送出去;接着把DatagramSocket中的数据读入接收用的DatagramPacket中(实际上是读入该DatagramPacket所封装的字节数组中)。客户端程序代码如下。

17.4.2 使用DatagramSocket发送、接收数据(3)
程序清单:codes\17\17.4\UdpClient.java
  1. public class UdpClient
  2. {
  3. // 定义发送数据报的目的地
  4. public static final int DEST_PORT = 30000;
  5. public static final String DEST_IP = "127.0.0.1";
  6. // 定义每个数据报的最大大小为4KB
  7. private static final int DATA_LEN = 4096;
  8. // 定义接收网络数据的字节数组
  9. byte[] inBuff = new byte[DATA_LEN];
  10. // 以指定的字节数组创建准备接收数据的DatagramPacket对象
  11. private DatagramPacket inPacket =
  12. new DatagramPacket(inBuff , inBuff.length);
  13. // 定义一个用于发送的DatagramPacket对象
  14. private DatagramPacket outPacket = null;
  15. public void init()throws IOException
  16. {
  17. try(
  18. // 创建一个客户端DatagramSocket,使用随机端口
  19. DatagramSocket socket = new DatagramSocket())
  20. {
  21. // 初始化发送用的DatagramSocket,它包含一个长度为0的字节数组
  22. outPacket = new DatagramPacket(new byte[0] , 0
  23. , InetAddress.getByName(DEST_IP) , DEST_PORT);
  24. // 创建键盘输入流
  25. Scanner scan = new Scanner(System.in);
  26. // 不断地读取键盘输入
  27. while(scan.hasNextLine())
  28. {
  29. // 将键盘输入的一行字符串转换成字节数组
  30. byte[] buff = scan.nextLine().getBytes();
  31. // 设置发送用的DatagramPacket中的字节数据
  32. outPacket.setData(buff);
  33. // 发送数据报
  34. socket.send(outPacket);
  35. // 读取Socket中的数据,读到的数据放在inPacket所封装的字节数组中
  36. socket.receive(inPacket);
  37. System.out.println(new String(inBuff , 0
  38. , inPacket.getLength()));
  39. }
  40. }
  41. }
  42. public static void main(String[] args)
  43. throws IOException
  44. {
  45. new UdpClient().init();
  46. }
  47. }



沒有留言:

張貼留言