当前位置: 代码迷 >> J2SE >> 求指教,建了个容易UDP传输,每次都会无故重发或者少发信息,单步执行又对,可是整个执行就错了
  详细解决方案

求指教,建了个容易UDP传输,每次都会无故重发或者少发信息,单步执行又对,可是整个执行就错了

热度:135   发布时间:2016-04-23 19:50:50.0
求指教,建了个简单UDP传输,每次都会无故重发或者少发信息,单步执行又对,可是整个执行就错了
建了一个UDP系统,Client端每次都会重发一次上次已经发送过的信息,有时候又会漏发一些,怎么看都不知道代码哪错了,单步执行也是对的,求各位大神们教教我呀
Client 的代码如下:
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.util.*;





public class ChatClient extends Frame{
TextField t1;
TextArea t2 ;
volatile String in = null;
volatile boolean flag = false;
ChatClient() {
this.setBounds(200, 200, 500, 500);
this.setVisible(true);
this.setResizable(true);
this.setLayout(new BorderLayout ());
 t1  = new TextField(10);
 t2 = new TextArea();
t1.addActionListener(new keyEvets() );


this.add(t1,BorderLayout.SOUTH);
this.add(t2,BorderLayout.CENTER);
pack();
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}

});
}


public static void main(String arg[]) throws Exception {
ChatClient chatclient = new ChatClient();
while(true) {
synchronized (chatclient) {
if(chatclient.flag ==false) {
continue;
}
if(chatclient.flag == true) {
ByteArrayOutputStream a = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(a);
//System.out.println(chatclient.in);
dos.writeUTF(chatclient.in);
chatclient.flag =false;
byte[] buf = new byte[1024];
buf = a.toByteArray();
String h = new String (buf);
System.out.println(h);
DatagramPacket ps = new DatagramPacket(buf,0,buf.length,new InetSocketAddress("127.0.0.1",6666));
DatagramSocket ds  = new DatagramSocket(4444);
dos.flush();
ds.send(ps);
ds.close();

}
}
}

}

class keyEvets implements ActionListener {
public void actionPerformed(ActionEvent e) {
synchronized (this) { 
flag =true;
String k = t1.getText();
in = k;
t2.setText("Client:"+k);
t1.setText("");
}
}

}
}

接受端Sever端的代码如下:
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;



public class ChatSever extends Frame{
TextField t1;
TextArea t2;
String in;
ChatSever() {
this.setBounds(200, 200, 500, 500);
this.setVisible(true);
this.setResizable(true);
this.setLayout(new BorderLayout ());
t1 = new TextField(10);
t2 = new TextArea();
this.add(t1,BorderLayout.SOUTH);
this.add(t2,BorderLayout.CENTER);
t1.addActionListener(new action());
pack();
this.addWindowListener(new WindowAdapter() {

public void windowClosing(WindowEvent e) {
System.exit(0);
}

});
}
public static void main(String arg[]) throws Exception {
ChatSever chatsever = new ChatSever(); 
DatagramSocket ds = new DatagramSocket(6666);

while(true) {

byte buf[] = new byte[1024];
DatagramPacket ps = new DatagramPacket(buf,0,buf.length);
System.out.println("ready");
ds.receive(ps);
ByteArrayInputStream a = new ByteArrayInputStream(buf);
DataInputStream dis = new DataInputStream(a);
String h = dis.readUTF();
System.out.println(h);
chatsever.t2.setText("Client:"+h);


}

}

public class action implements ActionListener {

public void actionPerformed(ActionEvent e) {

String k = t1.getText();
t2.setText("Client:"+k);
t1.setText("");

}

}
}

谢谢各位了,大恩不言谢!!
------解决思路----------------------
引用:
Quote: 引用:

问题就出在ChatSever的main方法这里
while(true) {
  if(chatclient.flag ==false) {
   continue;
 }
  if(..) ..
}
一个问题是chatclient.flag ==false时一直在空循环,浪费CPU资源,效率很低。
还有就是监听事件的线程和发送UDP的线程不是同一个,判断chatclient.flag时处理不好会出现问题。
最简单的方式就是把发送UDP的逻辑写到监听事件的方法里,在捕获到键盘输入后立即发送UDP,这样不会出现奇怪的线程同步问题。

嗯,谢谢回复我的问题,万分感谢,还有一个问题我一直没搞懂,希望大神你可以教教我:
(1)如果我的程序现在一个while(true)的死循环里面执行着,我加了一个键盘监听,监听的程序体在循环体外面,我想知道当我程序在死循环的过程中时,键盘监听到有输入,线程会不会从死循环跳出来执行监听的程序完以后在跳回到死循环里继续执行?
(2)还有键盘监听是只要键盘有输入是不是就线程就会直接跳出在执行的函数,转而去执行键盘监听的函数呢?(不加snychronized情况下)
这两个问题困扰很久了,希望大神指点迷津谢谢

1.不会从循环中跳出,按你代码的思路,是判断flag值得真假,来执行不同的逻辑,但始终在循环中。相当于监听线程修改flag,主线程读取flag。
2.监听线程和主线程是独立执行的,不会存在跳出的情况。ActionListener的actionPerformed是一个回调方法,当键盘有输入时,监听线程会调用你的回调方法。ActionListener是监听者模式的用法,你可以自己找相关资料看看。
  相关解决方案