java多客户端套接字服务器回显所有客户端

时间:2015-05-12 19:03:17

标签: java sockets

我正在研究多客户端套接字并且它的工作正常,但我想到如何通过将输入的字符串传输到所有客户端来公开通信。

例如,如果有3个客户端A,B和C,客户端A向服务器发送“foo”,我希望服务器也将“foo”流式传输到客户端B和C.

服务器模块:

package multiclient;

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

public class Server {

public static void main(String args[]) {

    Socket s = null;
    ServerSocket ss2 = null;
    System.out.println("Server Listening......");
    try {
        ss2 = new ServerSocket(4445); // can also use static final PORT_NUM , when defined

    } catch (IOException e) {
        e.printStackTrace();
        System.out.println("Server error");

    }

    while (true) {
        try {
            s = ss2.accept();
            System.out.println("connection Established");
            ServerThread st = new ServerThread(s);
            st.start();

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Connection Error");

        }
    }

  }

            }

class ServerThread extends Thread {

String line = null;
BufferedReader is = null;
PrintWriter os = null;
Socket s = null;

public ServerThread(Socket s) {
    this.s = s;
}

public void run() {
    try {
        is = new BufferedReader(new InputStreamReader(s.getInputStream()));
        os = new PrintWriter(s.getOutputStream());

    } catch (IOException e) {
        System.out.println("IO error in server thread");
    }

    try {
        line = is.readLine();
        while (line.compareTo("QUIT") != 0) {

            os.println(line);
            os.flush();
            System.out.println("Response to Client  :  " + line);
            line = is.readLine();
        }
    } catch (IOException e) {

        line = this.getName(); //reused String line for getting thread name
        System.out.println("IO Error/ Client " + line + " terminated abruptly");
    } catch (NullPointerException e) {
        line = this.getName(); //reused String line for getting thread name
        System.out.println("Client " + line + " Closed");
    } finally {
        try {
            System.out.println("Connection Closing..");
            if (is != null) {
                is.close();
                System.out.println(" Socket Input Stream Closed");
            }

            if (os != null) {
                os.close();
                System.out.println("Socket Out Closed");
            }
            if (s != null) {
                s.close();
                System.out.println("Socket Closed");
            }

        } catch (IOException ie) {
            System.out.println("Socket Close Error");
        }
    }//end finally
}

}

客户端模块:

package multiclient;

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

public class Client {

public static void main(String args[]) throws IOException{


InetAddress address=InetAddress.getLocalHost();
Socket s1=null;
String line=null;
BufferedReader br=null;
BufferedReader is=null;
PrintWriter os=null;

try {
    s1=new Socket(address, 4445); // You can use static final constant PORT_NUM
    br= new BufferedReader(new InputStreamReader(System.in));
    is=new BufferedReader(new InputStreamReader(s1.getInputStream()));
    os= new PrintWriter(s1.getOutputStream());
}
catch (IOException e){
    e.printStackTrace();
    System.err.print("IO Exception");
}

System.out.println("Client Address : "+address);
System.out.println("Enter Data to echo Server ( Enter QUIT to end):");

String response=null;
try{
    line=br.readLine(); 
    while(line.compareTo("QUIT")!=0){
            os.println(line);
            os.flush();
            response=is.readLine();
            System.out.println("Server Response : "+response);
            line=br.readLine();

        }



}
catch(IOException e){
    e.printStackTrace();
System.out.println("Socket read Error");
}
finally{

    is.close();os.close();br.close();s1.close();
            System.out.println("Connection Closed");

}

        }
          }

3 个答案:

答案 0 :(得分:0)

服务器可以保留所有客户端套接字的集合(直到一个被关闭)。当客户端消息到达时,服务器将其写入所有客户端套接字。

但是有一个问题,socket.write()是阻塞的,所以如果我们在循环中执行它,慢速客户端将阻塞其余的客户端。如果没有太多客户端,您可以生成一个新线程来写入每个单独的套接字。

在阻塞IO世界中,要实现真正的全双工协议,服务器必须为每个客户端提供两个线程,一个用于读取,一个用于写入。

如果你足够勇敢,你也可以尝试NIO ......

答案 1 :(得分:0)

有很多例子。搜索聊天服务器。如果您不介意使用框架,那么一个好的问题是Netty,请查看SecureChat示例以获取有效的代码。这是一个简短而有针对性的例子。

编辑:该链接将您带到示例代码。

答案 2 :(得分:0)

我建议:
1.将您创建的线程保存在ArrayList中 2.在Server中创建一个名为writeString的方法和一个锁

  private final Lock mutex = new ReentrantLock(true);
  private ArrayList<ServerThread> list = new ArrayList<ServerThread>();
  public void writeString(ServerThread t,String s)
  {
    mutex.lock();

   for(ServerThread th:list)
       if(th!=null && th!=t) //different from the thread receiving the string
          th.writeString(s);  //send string to other threads

    mutex.unlock();
  }

3。在ServerThread类中,实现writeString方法并添加一个Lock

  private final Lock mutex = new ReentrantLock(true);
  public void writeString(String s)
  {
     mutex.lock();
       os.println(s);
       os.flush();
    mutex.unlock();
   }

4。通过修改构造函数

保持对主服务器线程的引用
  //in ServerThread
  private Server parent=null;
  SeverThread(Socket s, Server parent)
  {
      this.parent=parent;
      /*the rest of the code*/
  }

  //in Server
  ServerThread st = new ServerThread(s,this);
  st.start();
  list.add(st);
  1. 当您在ServerThread中读取字符串时,请调用Server writeString方法以通知所有客户端

     parent.writeString(this,s); //calls the method we created at 2.