2015-01-13 221 views
1

我有一个简单的回声服务器,我想当连接用户输入任何东西到服务器,所有其他客户端和该客户端将得到消息+“| MOD”。Java TCP Echo服务器 - 广播

它现在不会发送给所有的客户端,但它应该和我只是不知道我的代码有什么问题,所以现在它只会发送消息+“| MOD”给发送消息的客户端,而不是所有其他人也应该如此。

我只是不明白,我有一个循环遍历所有的客户,但它仍然不会发送给所有。

SERVER:

package com.murplyx.server; 

import java.io.BufferedReader; 
import java.io.InputStreamReader; 
import java.io.PrintWriter; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.util.ArrayList; 

public class Server { 
    public static ServerSocket server; 
    public static ArrayList<Socket> clients = new ArrayList<Socket>(); 

    public static void broadcast(String message) { 
     try { 
      for (Socket socket : clients) { 
       PrintWriter out = new PrintWriter(socket.getOutputStream(), true); 

       out.println(message); 
      } 
     } catch(Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public static void main(String args[]) { 
     try { 
      server = new ServerSocket(9000); 

      while (true) { 
       clients.add(server.accept()); 

       for (Socket socket : clients) { 
        BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 

        String line = in.readLine(); 

        if (line != null) { 
         broadcast(line + " | MOD"); 
        } 
       } 
      } 
     } catch(Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

客户:

package com.murplyx.client; 

import java.io.BufferedReader; 
import java.io.InputStreamReader; 
import java.io.PrintWriter; 
import java.net.Socket; 

public class Client { 
    public static void main(String args[]) { 
     try { 
      while (true) { 
       Socket socket = new Socket("localhost", 9000); 

       BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
       PrintWriter out = new PrintWriter(socket.getOutputStream(), true); 

       BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); 

       out.println(input.readLine()); 

       System.out.println(in.readLine()); 

       socket.close(); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

请帮助。

非常感谢。

+0

在'Server.broadcast()',你应该在每次迭代结束时用'out.close()'关闭'PrintWriter'。 – colti

+0

如果我没有记错,关闭PrintWriter将关闭底层套接字;如果您需要不止一次播放,我不会关闭它。 – Aify

回答

2

你有一个问题是每个客户都会反复做无限次的read stdin, write socket, read socket, write stdout, ...

当你广播所有其他客户端仍然通常坐在read stdin阶段,所以他们不知道有什么东西在等待在套接字上读取。他们仍在等待用户输入内容。

最简单的选择之一是在每个客户端启动两个线程 - 一个只处理read stdin, write socket, ...,另一个处理read socket, write stdout

[另一个(可能更复杂)选项我们在同一时间使用Java NIO的调查既插座和标准输入可用输入

第二个问题是,你在服务器中调用accept阻塞,然后从每个套接字依次读取。您可能在一个线程中使用accept,并且每个客户端都有另一个线程只从客户端读取,并重播给其他线程。 NIO也可以是一个很好的选择 - 您可以轮询读取任何任何客户端。

+0

Plus服务器在接受中挂起。 – Fildor

+0

@Fildor那也是 - 还没有发现。 – Alnitak

+0

你可以请用代码显示吗?在发布我的问答后,我想,所有客户端都具有相同的知识产权,因为他们在测试他们时拥有相同的知识产权。 – super

0

我不能完全肯定的ArrayList如何与插座玩,所以我肯定会回去使用普通阵列为它(看到这里的编辑的代码Java EchoTCPServer - Send to all clients

有些事情,我看到,我觉得能到被修复:

客户端上:

- 停止关闭While循环中的套接字。在while循环外面关闭它(当客户端完成服务器时)。另外,在Loop外部声明套接字。

注意在这个:当客户端套接字连接到服务器时,它会自动给出一个设备端口,因此两个不同的设备将永远不会有相同的IP连接到服务器。 TCP连接由2个端口,服务器套接字和客户端套接字组成,套接字由[deviceip:port,serverip:port](iirc)表示。

- 另外,在客户端,每次移动while循环时都不需要声明新的读取器。把这一切放在外面。 while循环中唯一的东西应该是你的readline + print语句。

-readLine是一种阻塞方法。 (以防万一你不知道这意味着什么,这意味着readLine会让你的程序停留在那里,直到它实际读取一行为止,为了避免这种情况,你可以使用if语句和.ready()函数结合。功能检查,看看是否有什么要“读”,因此,如果没有输入,它不会被上“的readLine”卡住

在服务器:

样我前面说的,我会改回到使用正常的阵列

- 您的服务器仍然会卡住.accept()。因此,您将永远不能读取来自客户端的输入,除了在每次连接之后都进行一次输入之外,您可以使用线程反而听,它仍然会工作。

如:(此代码去与那是在我附链接代码(也是你的问题),把它放在你的服务器的while循环之前)

// create a tcp listener thread to deal with listening to clients 
Thread listenerThread = new Thread() { 
    public void run() { 
     String clientSentence; 

     while (true) { 
      //loop through each connected socket  
      for (int i = 0; i <= intLastSocket; i++) { 
       Socket z = clientSocket[i]; 
       //make sure the socket is not null or closed (can't do anything 
       //with closed or null sockets   
       if ((z != null) && (!z.isClosed())) { 
        try { 
         // Deal with TCP input here 
         BufferedReader input = new BufferedReader(new 
          InputStreamReader(z.getInputStream())); 
         // read in a line but only if there is one 
         if (input.ready()) { 
          clientSentence = input.readLine(); 
         } 
        } catch (IOException x) { 
         printTCP("IOException caught when reading in: " 
           + x.toString()); 
        } 
        if (clientSentence != null) { 
         System.out.println("Received from client: " 
           + clientSentence); 
         //send this message to the client 
         outputStream[i].println(clientSentence + " | MOD"); 
        } 

        // clear the input 
        clientSentence = null; 
       } 
      } 
     } 
    } 
}; 
listenerThread.start(); 
+0

与纯数组相比,在使用'ArrayList <>'时存在_zero_交互。 – Alnitak

+0

@Alnitak你能详细说明一下吗? – Aify

+1

_“我不完全确定ArrayLists如何使用套接字播放” - - 他们使用普通数组完全相同。 – Alnitak