黑马程序员技术交流社区

标题: UDP协议的聊天程序,使用两个线程分别发生和接收,却出错... [打印本页]

作者: 张世威    时间: 2012-7-16 22:37
标题: UDP协议的聊天程序,使用两个线程分别发生和接收,却出错...
本帖最后由 张世威 于 2012-7-17 12:05 编辑

      1、我用DatagramSocket写的聊天程序,用两个线程分别发送和接收数据,
               ①发生端:从控制台输入数据,每输入一行,便将数据发生出去
               ②接收端:监听端口,接收数据,并输出:发生端的ip和接收的数据
      
       2、在Eclipse里面,我输入数据,收到的数据却只有ip地址,没有数据部分,有时候还出现乱码,如下图。
               ①写几个英文字母的时候:就只会出来 127.0.0.1:
                  
              ②写汉字的是,好像能完全出来:127.0.0.1:张三
                  


        3、这真是奇了怪了,我还以为是用线程,两个线程之间互掐。于是我便在代码里面都添加了
              发送一次数据,线程休息一秒;接收一个数据,也休息一秒,还是这个模样,坑爹了。。

       4、代码:麻烦帮忙看看
  1. package day23;

  2. import java.io.*;
  3. import java.net.*;

  4. //1发送线程类
  5. class Send implements Runnable {
  6.         private DatagramSocket ds;
  7.         private InetAddress ip;
  8.         private int port;

  9.         public Send(DatagramSocket ds,InetAddress ip,int port) {
  10.                 this.ds = ds;
  11.                 this.ip=ip;
  12.                 this.port=port;
  13.         }

  14.         @Override
  15.         public void run() {
  16.                 SendAndRece sr = new SendAndRece();
  17.                 sr.send(ds,ip,port);

  18.         }
  19. }

  20. // 2接收线程类
  21. class Rece implements Runnable {
  22.         private DatagramSocket ds;

  23.         public Rece(DatagramSocket ds) {
  24.                 this.ds = ds;
  25.         }

  26.         @Override
  27.         public void run() {
  28.                 SendAndRece sr = new SendAndRece();
  29.                 sr.rece(ds);

  30.         }
  31. }

  32. // 4主调程序
  33. public class ChatDemo {
  34.         /**
  35.          * @param args
  36.          */
  37.         public static void main(String[] args) {

  38.                 // ①发送的DatagramSocket,加上端口
  39.                 try {
  40.                         //目的地址和端口号
  41.                         InetAddress ip = InetAddress.getByName("127.0.0.1");
  42.                         int port=10001;
  43.                         DatagramSocket dss = new DatagramSocket();
  44.                         new Thread(new Send(dss,ip,port)).start();

  45.                         
  46.                         // ②接收端DatagramSocket,加上端口
  47.                         DatagramSocket dsr=new DatagramSocket(10001);
  48.                         new Thread(new Rece(dsr)).start();
  49.                         
  50.                 } catch (SocketException e) {
  51.                         // TODO Auto-generated catch block
  52.                         e.printStackTrace();
  53.                 } catch (UnknownHostException e) {
  54.                         // TODO Auto-generated catch block
  55.                         e.printStackTrace();
  56.                 }
  57.         }

  58. }

  59. // 3业务类:定义一个类,两方法:发送和接收
  60. class SendAndRece {
  61.         // ①发送业务:发送udpsocket+目的地ip+目的端口
  62.         public void send(DatagramSocket ds, InetAddress ip,int port) {
  63.                 try {
  64.                         // 从键盘录入数据
  65.                         BufferedReader bufr = new BufferedReader(new InputStreamReader(
  66.                                         System.in));

  67.                         // 循环往bufr里面如
  68.                         String line = null;
  69.                         while ((line = bufr.readLine()) != null) {
  70.                                 if (line.equals("886")) {
  71.                                         break;
  72.                                 }
  73.                                 // 将数据封装到DatagramPacket
  74.                                 byte[] buf = line.getBytes();
  75.                                 DatagramPacket dp = new DatagramPacket(buf, buf.length, ip,
  76.                                                 port);
  77.                                 ds.send(dp);
  78.                                 //发完一个,休息1秒
  79.                                 try {
  80.                                         Thread.sleep(1000);
  81.                                 } catch (InterruptedException e) {
  82.                                         // TODO Auto-generated catch block
  83.                                         System.out.println("发送到失败");
  84.                                         e.printStackTrace();
  85.                                 }

  86.                         }
  87.                         ds.close();

  88.                 } catch (Exception e) {
  89.                         System.out.println(e);
  90.                 }

  91.         }

  92.         // ②接收业务:接收udpSocket
  93.         public void rece(DatagramSocket ds) {
  94.                 try {
  95.                         while (true) {
  96.                                 // ①定义一个数据包
  97.                                 byte[] buf = new byte[1024 * 64];
  98.                                 DatagramPacket dp = new DatagramPacket(buf, buf.length);

  99.                                 // ②将接收的数据包存放如dp中
  100.                                 ds.receive(dp);

  101.                                 // ③处理接收的数据
  102.                                 String ip = dp.getAddress().getHostAddress();
  103.                                 String data = new String(buf, 0, buf.length);
  104.                                 //System.out.println(data);
  105.                                 System.out.println(ip + ":" + data);
  106.                                 
  107.                                 //收完一个,休息1秒
  108.                                 try {
  109.                                         Thread.sleep(1000);
  110.                                 } catch (InterruptedException e) {
  111.                                         // TODO Auto-generated catch block
  112.                                         System.out.println("发送到失败");
  113.                                         e.printStackTrace();
  114.                                 }
  115.                                 
  116.                         }

  117.                 } catch (Exception e) {
  118.                         System.out.println(e);
  119.                 }

  120.         }
  121. }
复制代码
5、无奈之下,我想可能是Eclipse控制台显示效果吧,    于是我就用cmd控制台来试试。
         ①编译:javac ChatDemo.java 通过
         ②运行 :java ChatDemo      报错了。。。。Eclipse里面都能运行,控制台运行出错???
              错误如下图:
            

          ③竟然说找不到 ChatDemo?这怎么回事?


  
           
        

作者: 周恺    时间: 2012-7-17 08:02
本帖最后由 周恺 于 2012-7-17 08:11 编辑

你的接收方法的循环,我帮你改了一下.
while (true) {
                                // ①定义一个数据包
                                 byte[] buf = new byte[1024*64];
                               DatagramPacket dp = new DatagramPacket(buf,buf.length);

                                // ②将接收的数据包存放如dp中
                                ds.receive(dp);

                                // ③处理接收的数据
                                String ip = dp.getAddress().getHostAddress();
                                String data = new String(dp.getData(), 0, dp.getLength());//这里,你要打印的字符串,不能将所有的字节数组一起打印,而是接收多长的数据就打多长.
                                                                                                                          //使用dp.getData()方法获取数据缓冲区,dp.getLength())获取缓冲区长度.
                                //System.out.println(data);  
                                 System.out.println(ip + ":" + data);
                                
                                //收完一个,休息1秒
                                try {
                                        Thread.sleep(1000);
                                } catch (InterruptedException e) {
                                        // TODO Auto-generated catch block
                                        System.out.println("发送到失败");
                                        e.printStackTrace();
                                }
在我的控制台上已经运行成功.
另外,由于receive()方法是阻塞式方法,也就是说receive()如果接收不到数据包,就会一直等着,
不会跟发送线程"打架",是不会存在你说的那种线程问题的,你把sleep去掉再试试.

还有,你在控制台运行不了,是因为你的程序前面有包名,是在eclipse的工作区里面定义的,CLASSPATH找不到,当然运行不了.
作者: 张世威    时间: 2012-7-17 12:01
哥们,厉害呀,改完后就可以运行了。。谢谢你了




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2