DataOutputStream over TCP socket Deadlock

时间:2014-05-13 10:17:54

标签: java sockets tcp

我正在通过TCP sockat创建简单的聊天应用程序,但是当我尝试将数据发送到服务器进行登录时程序冻结,当我尝试调试客户端代码时,它停止在以Dataoutputstream.write开头的方法上  服务器代码

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()方法

时发生

和死锁

1 个答案:

答案 0 :(得分:1)

如果您对DataOutputStream的写入阻止,则通常意味着另一端未读取。

我建议在客户端添加一个单独的线程,它只会在服务器的另一端读取DataInputStream,直到连接关闭。此读者线程可以使用SwingUtils.invokeLater()

为事件循环计划事件

注意:这意味着您应该从新线程调用start(),并且您对GUI的所有更新都应通过invokeLater()

进行