客户端:
package com;import java.awt.TextArea;
public class ChatClient implements Runnable{
private static Text text;
private static Text txt_Area;
Socket s = null;                 //一个插座
DataOutputStream dos = null;     //向服务器写入数据
DataInputStream dis=null;        //从服务器读数据  Display      display;
Shell shell; private boolean bConnected=false;   //是否连接 //Thread tRecv=new Thread(new RecvThread());   //为客户端开一个线程 public static void main(String[] args) {
new ChatClient().launchFrame();
}
public void launchFrame(){  //初始化窗体
display = Display.getDefault(); //
shell = new Shell();               //存在应用程序的其他控件
shell.setToolTipText("\u804A\u5929\u7CFB\u7EDF\u5BA2\u6237\u7AEF\r\n");
shell.setImage(SWTResourceManager.getImage("F:\\\u56FE\u7247\\\u5F6C\u5F6C\\\u5F6C\u5F6C\u7ED9\u6211\u7684.jpg"));
shell.setSize(450, 342);
shell.setText("\u804A\u5929\u5BA2\u6237\u7AEF");
shell.setLayout(null); Button btn_Send = new Button(shell, SWT.NONE);
btn_Send.addMouseListener(new MouseAdapter() {
@Override
public void mouseDown(MouseEvent e) {
try{
send();
}catch(Exception e2){
e2.printStackTrace();
}
}
});
btn_Send.setBounds(340, 276, 68, 22);
btn_Send.setText("\u53D1\u9001"); text = new Text(shell, SWT.BORDER);
text.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
try {
keypressed(e);
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
text.setBounds(22, 219, 386, 51); txt_Area = new Text(shell, SWT.BORDER | SWT.READ_ONLY | SWT.WRAP | SWT.V_SCROLL | SWT.MULTI);
txt_Area.setBounds(24, 10, 388, 203); shell.open();
shell.layout(); text.forceFocus(); connect();   //连接服务器 //tRecv.start(); //为每个客户端 开一个线程
new Thread(this).start();        //开始线程
txt_Area.append("多线程已经开启");
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
} } disconnect();                                      //连接关闭
display.dispose();                                  //关闭窗体   
} public void keypressed(KeyEvent e) throws Exception{
if(e.keyCode==13){
send();    
}
}
public void send(){   //发送
String str = text.getText().trim();
txt_Area.setText(txt_Area.getText()+str+'\n');
text.setText(""); try {
// System.out.println(s);
dos.writeUTF(str);                             //发送数据
dos.flush();                                   //推一把
//dos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
public void connect(){       //连接
try {
s = new Socket("127.0.0.1",3333);
dos = new DataOutputStream(s.getOutputStream());//往服务器写
dis = new DataInputStream(s.getInputStream());    //从服务器读
System.out.println("connected!");
bConnected=true;
txt_Area.append("已经连接上服务器"+'\n');
}catch (Exception e) {
e.printStackTrace();
}
} public void disconnect() {    //结束
try {
dos.close();           
dis.close();
s.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void th(){ Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try{
while(bConnected){
String str=dis.readUTF();
System.out.println("数据接收成功");
txt_Area.append(str+'\n');
}
} catch (Exception e) {
System.out.println("退出了,bye!");

}
});
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
try {
th();
} catch (Exception e) {
System.exit(0);
}
}

}}
服务器端
package com;
import java.io.*;
import java.net.*;
import java.util.*;
public class ChatServer {
boolean started = false;
ServerSocket ss =null;

List<Client> clients=new ArrayList<Client>(); public static void main(String[] args) {
new ChatServer().start();
} public void start(){
try {
ss = new ServerSocket(3333);        //开放一个端口
started=true;                       //开始处理
}catch(BindException e){
System.out.println("端口使用中");
System.out.println("请关掉相关程序并重新运行服务器!");
System.exit(0);
}catch(IOException e){
e.printStackTrace();
} try{
while(started){                     //端口开放
Socket s=ss.accept();            //接受数据
Client c=new Client(s);         //传递参数
System.out.println("a client connected!");     //bConnected=true已经连接
new Thread(c).start();              //开始执行线程
clients.add(c);                    //执行完线程增加到clients中
}
}catch(IOException e){
e.printStackTrace();
}finally{
try{
ss.close();
}catch(IOException  e){
e.printStackTrace();
}
} }
class Client implements Runnable{
private Socket s;                          //每一个线程的接受数据
private DataInputStream dis =null;               //从客户端得到数据
private DataOutputStream dos=null;               //向客户端写出数据

private boolean bConnected = false;             //单独的一个线程的标记 ,是否开启 public void send(String str){                    //给每个客户端发送数据
try{
dos.writeUTF(str);
}catch(IOException e){
clients.remove(this);
System.out.println("对方退出了!我从List里面去掉了!");
}
}
public Client(Socket s){
this.s=s;
try{
dis= new DataInputStream(s.getInputStream());
dos=new DataOutputStream(s.getOutputStream());
bConnected=true;                          //已经连接 }catch(IOException e){
e.printStackTrace();
}
} @Override
public void run() {
try{
while(bConnected) {                       //当连接的时候
String str = dis.readUTF();            //阻塞世 傻傻的等待,每次接受一个就卡在这里了
System.out.println(str);
for(int i=0;i<clients.size();i++){
                         Client c=clients.get(i);
                         c.send(str);                      //把读到的数据发送出去
                         
}
}
} catch (EOFException e) {
System.out.println("客户端已经关闭!");     //客户端关闭的时候提示  已经结束
}catch(IOException e){
e.printStackTrace();
}finally{
try {
if(dis!=null) dis.close();            //最后关闭文件流,Socket
if(dos!=null) dos.close();
if(s!=null) s.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
哪位大哥可以帮我解决啊 搞了两天了 都不行  客户端一开就卡死了  怎么办啊

解决方案 »

  1.   

    好好看看你那几个循环  while循环
      

  2.   

    Reads in a string that has been encoded using a modified UTF-8 format.不是很確定,沒現場做實驗,依稀記得貌似readUTF讀入的如果不是一個modified UTF-8格式的字符串的話,可能會阻塞著吧用其他read方法驗證一下,比如readChar之類的
      

  3.   

    这样的程序可以这样调试在connect, send, receive 函数入口写一句输出
    在read, write前后各写一句输出根据输出情况判断大致问题所在
      

  4.   

    死循环,即便是在另一个线程里也是档不住的
    Display.getDefault().asyncExec 明显是会导致不停的new thread。
    不死就怪了。
    接80分...private void th(){Display.getDefault().asyncExec(new Runnable() {
    @Override
    public void run() {
    // TODO Auto-generated method stub
    try{
    while(bConnected){
    String str=dis.readUTF();
    System.out.println("数据接收成功");
    txt_Area.append(str+'\n');
    }
    } catch (Exception e) {
    System.out.println("退出了,bye!");

    }
    });
    }
    @Override
    public void run() {
    // TODO Auto-generated method stub
    while(true){
    try {
    th();
    } catch (Exception e) {
    System.exit(0);
    }
    }}
      

  5.   

    4楼指出了一个问题,这好改,asyncExce改成syncExec就行了。但是真正导致界面死的原因是不能将readUTF这样的阻塞动作放到asyncExec中去做,应该在asyncExec外面做。
    因为:asyncExec中执行的线程会阻塞GUI主线程。虽然和界面死没直接关系,但是Server还有点问题,楼主需要细改。从clients中移除Client对象和终止该客户端对应的Server端线程是两码事...
      

  6.   

    不同意楼上。asyncExec阻塞主线程他还叫什么async呢?
    这个方法明显是调用runable实例参数的start。就完事。不响应的原因是正是不阻塞然后一个死循环导致的。
    while(true){}楼主的client本身就实现了一个runable.
    所以把通信的事情放在run里执行也是很正确的。th()方法里可以直接写。
    String str=dis.readUTF();
    System.out.println("数据接收成功");
    txt_Area.append(str+'\n');
    }
    } catch (Exception e) {
    System.out.println("退出了,bye!");
      

  7.   

    阻塞不阻塞,和GUI主线程没关系。
    syncExec阻塞的是非主线程,asyncExec不阻塞的也是非主线程。不多说,贴5楼所说的修改方法的明细代码(客户端的run方法)如下: private String msg; @Override
    public void run() {
    while (true) {
    try {
    if (bConnected) {
    msg = dis.readUTF();
    System.out.println("数据接收成功");
    }
    } catch (Exception e) {
    System.out.println("退出了,bye!");
                                    break;
    }
    Display.getDefault().asyncExec(new Runnable() {
    @Override
    public void run() {
    txt_Area.append(msg + '\n');
    }
    });
    try {
    } catch (Exception e) {
    e.printStackTrace();
    System.exit(0);
    }
    } }
    因为线程体中代码少,上面改过的代码中用asyncExec或syncExec效果是一样的。
      

  8.   

    楼上这样改有可能先发的却后显示出来。
    另外:查了下swt的api syncExec 里面说The thread which calls this method is suspended until the runnable completes.
    aSyncExec 里面说The caller of this method continues to run in parallel, and is not notified when the runnable has completed另外:我的回复里笔误,是当前线程。
      

  9.   

    Exception in thread "Thread-0" org.eclipse.swt.SWTException: Device is disposed
    at org.eclipse.swt.SWT.error(SWT.java:3563)
    at org.eclipse.swt.SWT.error(SWT.java:3481)
    at org.eclipse.swt.SWT.error(SWT.java:3452)
    at org.eclipse.swt.widgets.Display.error(Display.java:1137)
    at org.eclipse.swt.widgets.Display.asyncExec(Display.java:630)
    at com.ChatClient$RecvThread.run(ChatClient.java:168)
    at java.lang.Thread.run(Thread.java:619)
    8楼得改法我试了  首先在每个客户端不会出现某一个客户端发的信息
    然后关闭服务器还报错为啥啊
      

  10.   

    这是因为主线程(GUI线程)退出了,但某个非主线程仍在执行。
    退出程序的时候如果直接用System.exit()就看不到这样的异常了。