2014-05-13 147 views
1

我通過TCP sockat創建簡單的聊天應用程序,但程序凍結時,當我嘗試將數據發送到服務器登錄,當我嘗試調試客戶端代碼時, Dataoutputstream.write Server代碼通過TCP套接字的DataOutputStream死鎖

import java.io.DataInputStream; 
import java.io.DataOutputStream; 
import java.io.IOException; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.util.ArrayList; 
import java.util.logging.Level; 
import java.util.logging.Logger; 

/* 
* To change this license header, choose License Headers in Project Properties. 
* To change this template file, choose Tools | Templates 
* and open the template in the editor. 
*/ 

/** 
* 
* @author HADDAD 
*/ 
public class Server { 
    final static int LOGIN=0,LOGOUT=1,BCAST=2,MCAST=3,SERVER=4; 
    private DataInputStream in; 
    private DataOutputStream out; 
    private Socket client; 
    private ServerSocket serverSocket; 
    private ArrayList<connection> conlist=new ArrayList<>(); 
    private boolean running; 
    private byte[] bytes=new byte[1000]; 
    private String msg; 
    private String[] msgs; 
    private int tag; 
    private static ServerGui serverGui=new ServerGui(); 
    public void runServer() 
    { 
     serverGui.jTextArea1.append("CHAT SERVER STARTED"); 
     running=true; 
     while(running) 
     { 
     try { 
      serverSocket =new ServerSocket(1676); 
      client =serverSocket.accept(); 
      in=new DataInputStream(client.getInputStream()); 
      // out=new DataOutputStream(client.getOutputStream()); 
      in.read(bytes); 
      msg=new String(bytes); 
      msgs=msg.split("-"); 
      tag=check(msgs); 
      switch(tag) 
        { 
        case LOGIN: 
        { 
         if(login(msgs[1], msgs[2], client)){} 
         else { System.out.println("login failed"); 
         serverGui.jTextArea1.append("login failed"); 
         } 
         break; 
        } 
        case LOGOUT: 
        { 
         if(logout(msgs[1])){} 
         else System.out.println("you are not logged in"); 
         break; 
        } 
        case SERVER: 
          recivemsg(msgs[1], msgs[0]); 
         break; 
        case MCAST: 
        { 
         multiCast(msgs); 
        } 
        case BCAST: 
        { 
         broadCast(msgs); 
        } 

        } 

     } catch (IOException ex) { 
      Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex); 
     } 


     } 
    } 
    public int check(String[] data) 
    { 
     return Integer.parseInt(data[data.length-1]); 

    } 
    public boolean login(String usr,String pass,Socket s) throws IOException 
    { 
     connection con=new connection(s, usr); 
     if(1==1){ 

     conlist.add(con); 
     writeMsgFromserver(con,true); 
     return true;} 
     else{ 
      writeMsgFromserver(con, false); 
      return false; 
     } 
    } 
    public boolean logout(String usr) 
    { 
     for(connection c:conlist) 
     { 
      if(c.getUsername().equals(usr)) 
      { 
       conlist.remove(c); 
       return true; 
      } 
      else return false; 
     } 
     return false; 
    } 
    public void recivemsg(String usr,String msg) 
    { 
     System.out.println(usr+":"+msg); 
    } 
    public void multiCast(String[] msgs) throws IOException 
    { 
     Socket s; 
     DataOutputStream dos; 
     if(conlist.isEmpty()) 
     { 
      serverGui.jTextArea1.append(System.lineSeparator()); 
      serverGui.jTextArea1.append("there is no other users"); 
      System.out.println("there is no other users"); 
     } 
     else 
      for(connection c:conlist) 
      { 
       s=c.getSocket(); 
       dos=new DataOutputStream(s.getOutputStream()); 
       dos.write(Format(msgs).getBytes()); 

      } 
    } 
    public void writeMsgFromserver(connection c,boolean b) throws IOException 
    { 
     if(b==true){ 
     String m="accept"+"-"+"Server"+"-"+"empty"+"-"+"empty"+"-"+SERVER; 
     Socket s=c.getSocket(); 
     DataOutputStream dos=new DataOutputStream(s.getOutputStream()); 
     dos.write(m.getBytes()); 
     serverGui.jTextArea1.append(System.lineSeparator()); 
     serverGui.jTextArea1.append("Server:"+c.getUsername()+" logged in"); 
     } 
     else 
     { 
      String m="refuse"+"-"+"Server"+"-"+"empty"+"-"+"empty"+"-"+SERVER; 
     Socket s=c.getSocket(); 
     DataOutputStream dos=new DataOutputStream(s.getOutputStream()); 
     dos.write(m.getBytes()); 
     serverGui.jTextArea1.append(System.lineSeparator()); 
     serverGui.jTextArea1.append("Server:"+c.getUsername()+" registeration failed"); 
     } 


    } 
    public void broadCast(String[] msgs) throws IOException 
    { 
     Socket rcvrsocket; 
     DataOutputStream dos; 
     for(connection c:conlist) 
     { 
      if(c.getUsername().equals(msgs[1])) 
      { 
       rcvrsocket=c.getSocket(); 
       dos=new DataOutputStream(rcvrsocket.getOutputStream()); 
       dos.write(Format(msgs).getBytes()); 
       return ; 
      } 

     } 
     System.out.println("user:"+msgs[1]+"Not found!"); 
     serverGui.jTextArea1.append(System.lineSeparator()); 
     serverGui.jTextArea1.append("user:"+msgs[1]+"Not found!"); 
    } 
    public String Format(String[] m) 
    { 
     StringBuilder builder=new StringBuilder(); 
     for (int i=0;i<m.length;i++) 
     { 
      builder.append(m[i]); 
      if(i!=m.length-1) 
      builder.append('-'); 
     } 
     return builder.toString(); 
    } 
    public static void main(String[] args){ 
     Server s=new Server(); 

     serverGui.main(args); 
     s.runServer(); 
    } 
} 

客戶端代碼

import java.io.DataInputStream; 
import java.io.DataOutputStream; 
import java.io.IOException; 
import java.net.Socket; 

/* 
* To change this license header, choose License Headers in Project Properties. 
* To change this template file, choose Tools | Templates 
* and open the template in the editor. 
*/ 

/** 
* 
* @author HADDAD 
*/ 
public class client { 
    private String usrname; 
    private String pass; 
    private int port; 
    private Socket socket; 
    private DataInputStream dis; 
    private DataOutputStream dos; 
    private boolean loggedin=false; 
    private byte[] bytes; 
    private ClientGui cg; 

    public boolean isLoggedin() { 
     return loggedin; 
    } 

    public void setLoggedin(boolean loggedin) { 
     this.loggedin = loggedin; 
    } 

    public client(String usrname, String pass, int port,ClientGui cg) { 
     bytes=new byte[1000]; 
     this.usrname = usrname; 
     this.pass = pass; 
     this.port = port; 
     this.cg=cg; 

    } 
    public void start() throws IOException{ 
      socket =new Socket("localhost", port); 
     dis=new DataInputStream(socket.getInputStream()); 
     dos=new DataOutputStream(socket.getOutputStream()); 
     sendloginmsg(); 
     dis.read(bytes); 
     String m=new String(bytes); 
     String msgs[]=recive(m); 
     if(msgs[1].equals("accept")) 
     { 
      cg.jTextArea1.append(System.lineSeparator()); 
      cg.jTextArea1.append("logain successed"); 
     } 
     else 
     { 
      cg.jTextArea1.append(System.lineSeparator()); 
      cg.jTextArea1.append("logain failed check your username or password"); 
      return; 
     } 
     while(true) 
     { 
     dis.read(bytes); 
     m=new String(bytes); 
     msgs=recive(m); 
      writeToGui(msgs); 
     } 
    } 
    public void sendMsg(String msg) throws IOException 
    { 
     dos.write(msg.getBytes()); 
     dos.flush(); 
    } 
    public String[] recive(String msg) 
    { 
     String[] msgs=msg.split("-"); 
     String[] a={msgs[0],msgs[1],msgs[msgs.length-1]}; 
     return a; 
    } 
    public void writeToGui(String[] mm) 
    { 
     switch(Integer.parseInt(mm[mm.length-1])) 
      { 
      case Server.SERVER: 
      { 
       cg.jTextArea1.append(System.lineSeparator()); 
      cg.jTextArea1.append("Server:"+mm[0]); 

      break; 
      } 
      case Server.MCAST : 
      { 
        cg.jTextArea1.append(System.lineSeparator()); 
      cg.jTextArea1.append(mm[1]+":"+mm[0]); 
      break; 
      } 
      case Server.BCAST: 
      { 
        cg.jTextArea1.append(System.lineSeparator()); 
      cg.jTextArea1.append(mm[1]+":"+mm[0]); 
      break; 
      } 
      } 

    } 
    public void sendloginmsg() throws IOException 
    { 
     String tag=String.valueOf(Server.LOGIN); 
       String[] m={"Hello!",usrname,pass,"Server",tag}; 
       sendMsg(Format(m)); 
    } 
    public String Format(String[] m) 
    { 
     StringBuilder builder=new StringBuilder(); 
     for (int i=0;i<m.length;i++) 
     { 
      builder.append(m[i]); 
      if(i!=m.length-1) 
      builder.append('-'); 
     } 
     return builder.toString(); 
    } 
} 

連接代碼

import java.net.Socket; 

/* 
* To change this license header, choose License Headers in Project Properties. 
* To change this template file, choose Tools | Templates 
* and open the template in the editor. 
*/ 

/** 
* 
* @author HADDAD 
*/ 
public class connection { 
    private Socket socket; 
    private String username; 

    public connection(Socket socket, String username) { 
     this.socket = socket; 
     this.username = username; 
    } 

    public Socket getSocket() { 
     return socket; 
    } 

    public String getUsername() { 
     return username; 
    } 

} 

和死鎖時,我打電話sendMsg()方法

+0

嘗試調試發生.. – Juanpe

+0

我嘗試了很多次,當我到達dos裏面的sendMsg方法它凍結與noo異常 – Tony

+0

所以它與您的服務器的問題,如果沒有例外意味着什麼都沒有出錯,只是nothig正在發生,採取更好看在你的服務器代碼 – Juanpe

回答

1

如果你到DataOutputStream類塊寫操作,這通常意味着另一端不讀發生。

我建議向客戶端添加一個單獨的線程,該線程除了將DataInputStream的另一端讀取到服務器之外,直到連接關閉。這種讀取器線程可以安排與SwingUtils.invokeLater()事件循環事件

注:這意味着你的start()應該從一個新的線程被調用,所有更新的GUI應通過一個invokeLater()

+0

我在java.awt.EventQueue.invokeLater中創建了新的runnable – Tony

+0

我調用了gui中的start方法,但是我得到了相同的結果 – Tony

+0

@Tony invokeLater將它添加到事件隊列中,start()將運行代碼您從中調用它的線程。無論哪種方式,你正在使用唯一的事件線程來阻止讀取,這意味着它不會做任何事情(如更新屏幕)您需要啓動一個新的'Thread'來運行您的Runnable。 –