【问题标题】:Simple Client-Server Application - Socket problems简单的客户端-服务器应用程序 - 套接字问题
【发布时间】:2013-06-17 08:06:36
【问题描述】:

我正在使用 TCP Sockets 编写一个简单的客户端-服务器应用程序。它采用多线程原理,允许多个客户端连接到同一服务器。

我在弄清楚我使用套接字时遇到的一些错误时遇到了一些麻烦,正如您可能会说的那样,我在这个环境中还很陌生。

我将向您展示我拥有的代码以及从中获得的输出,但基本上问题在于客户端与服务器的连接,我运行了所有代码但仍然找不到有什么问题。

服务器:

public static ArrayList<String> userList = new ArrayList<String>();
public static int index;
public static String date;
public static void main(String args[]) throws Exception {//inicio main      


    ServerSocket server = new ServerSocket(6500);   //Create socket on port 6500
    System.out.println ("Server started on port 6500");     
    while (true){   //Waiting for clients
        System.out.println("Server waiting for client connections..");
        Socket socket = null;
        BufferedReader reader = new BufferedReader(new FileReader("C:\\UNIV\\Redes\\workspace\\Copy of Ex_4.3_Teste\\lists\\blacklist.txt"));
        String line = null;
        socket = server.accept();

        // Blacklist verification
        while ((line = reader.readLine()) != null) {
            if (line.equals(socket.getInetAddress().toString())) {
                System.out.println("IP Blacklisted: " + socket.getInetAddress().toString());
                System.out.println("Closing connection to " + socket.getInetAddress().toString());
                PrintStream checkBlack = new PrintStream(socket.getOutputStream(),true);
                checkBlack.println("***BLACKLISTED***");
                reader.close();
                checkBlack.close();
                socket.close();
                break; 
            }
        }//End of Blacklist Verification

        //Sending feedback in case of approved client
        try { 
        PrintStream checkBlack = new PrintStream(socket.getOutputStream(),true);
        checkBlack.println("***NBLACKLISTED***");
        checkBlack.close();
        } catch (SocketException e) {

        }
        userList.add(socket.getInetAddress().toString()); //Add connected user's IP to USERLIST
        System.out.println("New connection..");
        System.out.println("Size of UserList: " + userList.size());
        Thread t = new Thread(new EchoClientThread(socket)); 

        t.start(); //Starting Client Thread


    }//End of Waiting for Clients       
}//End of Main  

public static class EchoClientThread implements Runnable{
    private Socket s;
    public EchoClientThread(Socket socket) {
        this.s = socket;
    }
    public void run() { 
        String threadName = Thread.currentThread().getName();   //Thread Name
        String stringClient = s.getInetAddress().toString();    //Client IP
        System.out.println("Connected to " + stringClient); 

        try{                
            BufferedReader input = new BufferedReader(
                    new InputStreamReader(s.getInputStream()));         
            PrintStream output = new PrintStream(
                    s.getOutputStream(),true);
            String line;
            while ((line = input.readLine()) !=null) {  //Input Cycle   

                System.out.println (stringClient+": "+threadName+": "+line);    //Print command from client

                if (line.equalsIgnoreCase("9")){ //Exit
                    break;
                }

                else if (line.equalsIgnoreCase("1")){   //Send List of Online Users
                    System.out.println("Option 1: Sending list of online users to " + stringClient);
                    output.println(" ");
                    output.println("List of Online Users:");
                    output.println(" ");
                    for(int i=0;i<userList.size();i++){
                        output.println(userList.get(i));
                    }
                }

                else if (line.equalsIgnoreCase("2")) {  //Send message to a single user
                    System.out.println("Nothing here yet..");
                }

                else if (line.equalsIgnoreCase("3")) {  //Send message to all the online users
                    System.out.println("Nothing here yet..");
                }

                else if (line.equalsIgnoreCase("4")){   //Send User Blacklist
                    System.out.println("Option 4: Sending user blacklist to " + stringClient);
                    BufferedReader reader = new BufferedReader(new FileReader("C:\\UNIV\\Redes\\workspace\\Copy of Ex_4.3_Teste\\lists\\blacklist.txt"));
                    String lineRead = null;
                    output.println(" ");
                    output.println("User Blacklist:");
                    output.println(" ");
                    while ((lineRead = reader.readLine()) != null) {
                        output.println(lineRead);
                    }
                    reader.close();
                }

                else{
                    output.println("Unknown command.");
                }   

                output.println("***CLOSE***");  //Closes client's input cycle
                output.println("***NBLACKLISTED***");   //Sending feedback in case of approved client                       
            }//Input Cycle End

            output.println("See you later!"); 
            input.close();  //Closes inputStream 
            output.close(); //Closes outputStream
            s.close();  //Closes Socket                         
        }
        catch (Exception e){
            System.err.println("Server Side Error!");
            System.out.println(e);
        }
        userList.remove(s.getInetAddress().toString());
        System.out.println("Client "+ stringClient+" was disconnected!");                   
    }//End of run()  
}//End of EchoClientThread
}//End of EchoServerThread

客户:

public static void main(String args[]) throws Exception {
    if (args.length !=1){
        System.err.println ("usage: java EchoClient2 <host>");
        System.exit(1);
    }               
    String host = args[0];
    int port = 6500;
    String cmd, line;
    Socket socket = new Socket(host,port);
    BufferedReader input = new BufferedReader(
            new InputStreamReader(socket.getInputStream()));
    PrintStream output = new PrintStream(socket.getOutputStream(),true);

        while( true ) {//Input cycle 

            Scanner scan = new Scanner (System.in);
            if (input.readLine().equals("***BLACKLISTED***")) {
                System.out.println("IP is Blacklisted");
                break;
            }
            System.out.println(" ");
            System.out.println("CLIENT MENU");
            System.out.println(" ");
            System.out.println("1 - List on-line users");
            System.out.println("2 - Send message to a single user");
            System.out.println("3 - Send message to all on-line users");
            System.out.println("4 - List Blacklisted Users");
            System.out.println("9 - Exit");
            System.out.println(" ");
            System.out.print(host+":"+port+"#>");   //Command prompt            
            cmd = scan.nextLine();  //Scanning command to send to the server    
            output.println(cmd);    //Sending command to the server

            if ( cmd.equalsIgnoreCase("9")){
                System.out.println("Exiting..");
                break;
            } 

            try {
            while (!(line = input.readLine()).equals("***CLOSE***")) {  //Input Cycle                           
            System.out.println (line);  //Prints server answer      
            }
            } catch (Exception e) {
                System.err.println("Client Side Error!");
                System.out.println(e);
                break;
            }

        }//End of Cycle

    System.out.println("Connection Terminated");
    input.close();  //Closes inputStream
    output.close(); //Closes outputStream
    socket.close(); //Closes Socket 
}
}

所以服务器以以下输出正常启动:

Server started on port 6500
Server waiting for client connections..

但一旦我尝试与客户端连接,就会发生这种情况:

服务器端:

Server started on port 6500
Server waiting for client connections..
New connection..
Size of UserList: 1
Server waiting for client connections..
Connected to /127.0.0.1
java.net.SocketException: Socket is closed
Server Side Error!
Client /127.0.0.1 was disconnected!

但在客户端,它仍然显示输入菜单和命令提示符,如下所示:

CLIENT MENU

1 - List on-line users
2 - Send message to a single user
3 - Send message to all on-line users
4 - List Blacklisted Users
9 - Exit

127.0.0.1:6500#>

当我在客户端提示符上输入内容时,我得到:

127.0.0.1:6500#>1
Client Side Error!
java.net.SocketException: Software caused connection abort: recv failed
Connection Terminated

我知道错误的含义,Socket is closed 几乎是不言自明的,但我就是找不到导致套接字关闭的代码问题。

非常感谢任何帮助。

【问题讨论】:

  • 你试过调试你的服务器代码吗?在我看来,您的服务器只是因为异常而关闭了套接字。如果您也可以发布例外情况,那也会有所帮助
  • 当客户端尝试连接到服务器时,我得到的唯一例外是java.net.SocketException: Socket is closed。调试并没有帮助我,这就是我在这里问这个的部分原因。显然它在System.out.println("Connected to "+ stringClient) 之后立即关闭了套接字,但我不知道为什么。

标签: java sockets client-server


【解决方案1】:

你的黑名单机制不太对。

当您关闭与套接字关联的流时,它也会关闭套接字。

所以服务器正在关闭它获得的任何套接字,然后将其交给一个线程, 它尝试使用套接字并失败。

    // Blacklist verification
    while ((line = reader.readLine()) != null) {
        // blah blah blah
    }//End of Blacklist Verification

    //Sending feedback in case of approved client
    try { 
        PrintStream checkBlack = new PrintStream(socket.getOutputStream(),true);
        checkBlack.println("***NBLACKLISTED***");
        checkBlack.close();  // <== why are you closing the stream?
    } catch (SocketException e) {

    }

试试这个

    // Blacklist verification
    while ((line = reader.readLine()) != null) {
        // blah blah blah
    }//End of Blacklist Verification

    //Sending feedback in case of approved client
    try { 
        socket.getOutputStream().write("***NBLACKLISTED***\n".getBytes());
    } catch (SocketException e) {
        e.printStackTrace();
    }

调试器是你的朋友。

【讨论】:

  • 我想我需要关闭 Stream 才能为命令输入打开一个新的。好吧,我想那时不会。每天都是学习日^^非常感谢。
  • PrintStream 包裹着 SocketStream,所以你可以让它挂起。除非您希望基础流关闭,否则不要关闭。流可能会让人感到困惑,有些你必须关闭其他你必须独自离开的。
  • 哦,我明白了,socket.getOutputStream().write() 只是写入它必须写入的内容并在不关闭 Socket 的情况下关闭 Stream ?
  • 没有流保持打开状态。当您创建套接字时,您会创建一个上游(输出)和一个下游(输入)。每个都只能有一个,因此它们需要在套接字的生命周期内保持打开状态。当您需要发送或接收某些内容时,您只需获取适当的 Stream 并读取或写入。每当您在套接字上调用 get***Stream 时,您都会为 *** 获得相同的流,如果您有多个线程使用同一个套接字,这很重要。当套接字关闭时,将为您清理流。
  • 这有点令人困惑,但我想我现在明白了,感谢您抽出宝贵时间:)
猜你喜欢
  • 2014-01-14
  • 1970-01-01
  • 1970-01-01
  • 2021-01-21
  • 2018-01-30
  • 2020-05-24
  • 1970-01-01
  • 1970-01-01
  • 2015-12-25
相关资源
最近更新 更多