2017-09-12 8 views
1

私はチャットサーバーを作成しています。ソケットサーバーとスレッドを使用しています。私は、サーバーChatServer.java、ThreadedServer.java、およびMain.javaに3つのクラスを持っています。 My Clientには2つのChatClient.java、Main.javaがあります。メッセージをクライアントからサーバーに送信するときに、サーバーがすべてのクライアントにメッセージを送信するようにする必要があります。Java - すべてのクライアントにメッセージを送信

ChatServer.java

package server; 

import java.io.*; 
import java.net.*; 

public class ChatServer { 
    protected Socket s; 
    protected Socket ss; 
    public ChatServer() { 
     try { 
      ServerSocket ss=new ServerSocket(6969); 
      Runtime.getRuntime().addShutdownHook(new Thread() { 
       public void main(String []args) throws IOException { 
        ss.close(); 
       } 
      }); 
      while (true) { 
       Socket s =ss.accept(); 
       new ThreadedServer(s).start(); 
      } 
     }catch(Exception e) { 
      System.out.println(e); 
     } 
     new ThreadedServer(s).start(); 
     } 
} 

ThreadedServer.java

package server; 

import java.io.*; 
import java.net.*; 

public class ThreadedServer extends Thread{ 
    protected Socket socket; 

    public ThreadedServer(Socket clientSocket) { 
     this.socket = clientSocket; 
    } 

    public void run() { 
     try { 
      DataInputStream dis = new DataInputStream(socket.getInputStream()); 
      DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); 
      while (true) { 
       String str=(String)dis.readUTF(); 
       String remote = socket.getInetAddress().toString(); 
       String newmes = remote + ": " + str; 
       dos.writeUTF(newmes); 
       System.out.println(newmes); 
       if (str.toUpperCase() == "QUIT") { 
        socket.close(); 
        break; 
       }else if (str.toUpperCase() == "EXIT") { 
        socket.close(); 
        break; 
       } 
      } 
     }catch(Exception e) { 
      System.out.println(e); 
     } 
    } 
} 

Main.java(サーバー) パッケージサーバ。ここで

public class Main { 
    public static void main(String[] args) { 
     ChatServer chat = new ChatServer(); 
    } 
} 

はClient.javaの

ChatClient.java パッケージクライアントです。

import java.io.*; 
import java.net.*; 

public class ChatClient { 

    public ChatClient() { 
     try { 
      Socket s = new Socket("10.4.27.29",6969); 
      Runtime.getRuntime().addShutdownHook(new Thread() { 
       public void main(String []args) throws IOException { 
        s.close(); 
       } 
      }); 
      DataOutputStream dos = new DataOutputStream(s.getOutputStream()); 
      DataInputStream dis = new DataInputStream(s.getInputStream()); 
      while (true) { 
       String message = System.console().readLine(); 
       dos.writeUTF(message); 
       System.out.println(dis.readUTF()); 
      } 
     }catch(Exception e) { 
      System.out.println(e); 
     } 
    } 
} 

Main.java(クライアント)

package client; 

public class Main { 
    public static void main(String[] args) { 
     ChatClient chat = new ChatClient(); 

    } 
} 

してくださいすべてのヘルプは素晴らしいだろう。

また、これをより良くするための任意のアイデアは高く評価されます。ありがとう!!

+0

"これはよりよいづくり" について。ノンブロッキングソケットIOの使用を検討してください。すべてのクライアントにメッセージを送信することについて:あなたのサーバーにソケットのセットを保存し、接続されている各ソケットにメッセージを送信します。 – petul

答えて

0

これを試してみてください。これは私が作ったものです。

ChatServer.java

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

/** 
* A multithreaded chat room server. When a client connects the 
* server requests a screen name by sending the client the 
* text "SUBMITNAME", and keeps requesting a name until 
* a unique one is received. After a client submits a unique 
* name, the server acknowledges with "NAMEACCEPTED". Then 
* all messages from that client will be broadcast to all other 
* clients that have submitted a unique screen name. The 
* broadcast messages are prefixed with "MESSAGE ". 
* 
* Because this is just a teaching example to illustrate a simple 
* chat server, there are a few features that have been left out. 
* Two are very useful and belong in production code: 
* 
*  1. The protocol should be enhanced so that the client can 
*  send clean disconnect messages to the server. 
* 
*  2. The server should do some logging. 
*/ 
public class ChatServer { 

    /** 
    * The port that the server listens on. 
    */ 
    private static final int PORT = 9001; 

    /** 
    * The set of all names of clients in the chat room. Maintained 
    * so that we can check that new clients are not registering name 
    * already in use. 
    */ 
    private static HashSet<String> names = new HashSet<String>(); 

    /** 
    * The set of all the print writers for all the clients. This 
    * set is kept so we can easily broadcast messages. 
    */ 
    private static HashSet<PrintWriter> writers = new HashSet<PrintWriter>(); 

    /** 
    * The appplication main method, which just listens on a port and 
    * spawns handler threads. 
    */ 
    public static void main(String[] args) throws Exception { 
    System.out.println("The chat server is running."); 
    ServerSocket listener = new ServerSocket(PORT); 
    try { 
     while (true) { 
     new Handler(listener.accept()).start(); 
     } 
    } finally { 
     listener.close(); 
    } 
    } 

    /** 
    * A handler thread class. Handlers are spawned from the listening 
    * loop and are responsible for a dealing with a single client 
    * and broadcasting its messages. 
    */ 
    private static class Handler extends Thread { 
    private String name; 
    private Socket socket; 
    private BufferedReader in; 
    private PrintWriter out; 

    /** 
     * Constructs a handler thread, squirreling away the socket. 
     * All the interesting work is done in the run method. 
     */ 
    public Handler(Socket socket) { 
     this.socket = socket; 
    } 

    /** 
     * Services this thread's client by repeatedly requesting a 
     * screen name until a unique one has been submitted, then 
     * acknowledges the name and registers the output stream for 
     * the client in a global set, then repeatedly gets inputs and 
     * broadcasts them. 
     */ 
    public void run() { 
     try { 

     // Create character streams for the socket. 
     in = new BufferedReader(new InputStreamReader(
            socket.getInputStream())); 
     out = new PrintWriter(socket.getOutputStream(), true); 

     // Request a name from this client. Keep requesting until 
     // a name is submitted that is not already used. Note that 
     // checking for the existence of a name and adding the name 
     // must be done while locking the set of names. 
     while (true) { 
      out.println("SUBMITNAME"); 
      name = in.readLine(); 
      if (name == null) { 
      return; 
      } 
      synchronized (names) { 
      if (!names.contains(name)) { 
       names.add(name); 
       break; 
      } 
      } 
     } 

     // Now that a successful name has been chosen, add the 
     // socket's print writer to the set of all writers so 
     // this client can receive broadcast messages. 
     out.println("NAMEACCEPTED"); 
     writers.add(out); 

     // Accept messages from this client and broadcast them. 
     // Ignore other clients that cannot be broadcasted to. 
     while (true) { 
      String input = in.readLine(); 
      if (input == null) { 
      return; 
      } 
      for (PrintWriter writer : writers) { 
      writer.println("MESSAGE " + name + ": " + input); 
      } 
     } 
     } catch (IOException e) { 
     System.out.println(e); 
     } finally { 
     // This client is going down! Remove its name and its print 
     // writer from the sets, and close its socket. 
     if (name != null) { 
      names.remove(name); 
     } 
     if (out != null) { 
      writers.remove(out); 
     } 
     try { 
      socket.close(); 
     } catch (IOException e) { 
     } 
     } 
    } 
    } 
} 

ChatClient.java

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.PrintWriter; 
import java.net.Socket; 

import javax.swing.JFrame; 
import javax.swing.JOptionPane; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 
import javax.swing.JTextField; 

/** 
* A simple Swing-based client for the chat server. Graphically 
* it is a frame with a text field for entering messages and a 
* textarea to see the whole dialog. 
* 
* The client follows the Chat Protocol which is as follows. 
* When the server sends "SUBMITNAME" the client replies with the 
* desired screen name. The server will keep sending "SUBMITNAME" 
* requests as long as the client submits screen names that are 
* already in use. When the server sends a line beginning 
* with "NAMEACCEPTED" the client is now allowed to start 
* sending the server arbitrary strings to be broadcast to all 
* chatters connected to the server. When the server sends a 
* line beginning with "MESSAGE " then all characters following 
* this string should be displayed in its message area. 
*/ 
public class ChatClient { 

    BufferedReader in; 
    PrintWriter out; 
    JFrame frame = new JFrame("Chatter"); 
    JTextField textField = new JTextField(40); 
    JTextArea messageArea = new JTextArea(8, 40); 

    /** 
    * Constructs the client by laying out the GUI and registering a 
    * listener with the textfield so that pressing Return in the 
    * listener sends the textfield contents to the server. Note 
    * however that the textfield is initially NOT editable, and 
    * only becomes editable AFTER the client receives the NAMEACCEPTED 
    * message from the server. 
    */ 
    public ChatClient() { 

    // Layout GUI 
    textField.setEditable(false); 
    messageArea.setEditable(false); 
    frame.getContentPane().add(textField, "North"); 
    frame.getContentPane().add(new JScrollPane(messageArea), "Center"); 
    frame.pack(); 

    // Add Listeners 
    textField.addActionListener(new ActionListener() { 
     /** 
     * Responds to pressing the enter key in the textfield by sending 
     * the contents of the text field to the server. Then clear 
     * the text area in preparation for the next message. 
     */ 
     public void actionPerformed(ActionEvent e) { 
      out.println(textField.getText()); 
      textField.setText(""); 
     } 
     }); 
    } 

    /** 
    * Prompt for and return the address of the server. 
    */ 
    private String getServerAddress() { 
    return JOptionPane.showInputDialog(
         frame, 
         "Enter IP Address of the Server:", 
         "Welcome to the Chatter", 
         JOptionPane.QUESTION_MESSAGE); 
    } 

    /** 
    * Prompt for and return the desired screen name. 
    */ 
    private String getName() { 
    return JOptionPane.showInputDialog(
         frame, 
         "Choose a screen name:", 
         "Screen name selection", 
         JOptionPane.PLAIN_MESSAGE); 
    } 

    /** 
    * Connects to the server then enters the processing loop. 
    */ 
    private void run() throws IOException { 

    // Make connection and initialize streams 
    String serverAddress = getServerAddress(); 
    Socket socket = new Socket(serverAddress, 9001); 
    in = new BufferedReader(new InputStreamReader(
           socket.getInputStream())); 
    out = new PrintWriter(socket.getOutputStream(), true); 

    // Process all messages from server, according to the protocol. 
    while (true) { 
     String line = in.readLine(); 
     if (line.startsWith("SUBMITNAME")) { 
     out.println(getName()); 
     } else if (line.startsWith("NAMEACCEPTED")) { 
     textField.setEditable(true); 
     } else if (line.startsWith("MESSAGE")) { 
     messageArea.append(line.substring(8) + "\n"); 
     } 
    } 
    } 

    /** 
    * Runs the client as an application with a closeable frame. 
    */ 
    public static void main(String[] args) throws Exception { 
    ChatClient client = new ChatClient(); 
    client.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    client.frame.setVisible(true); 
    client.run(); 
    } 
} 
+0

私は自分のコードに追加する方法を探しています。これはsnarkyと聞こえるかもしれませんが、私はコードで作業したいので、私は最初から構築しようとしているので、このコンセプトを理解できませんでした。 –

+0

さて、私の例を見て、あなたと同様のロジックを実装してください。あなたは私のコード全体を使う必要はありませんが、あなたが望むものの「実例」を持っていると助けになります。私はクライアント上でJava Swingを使用していますが、それはあなたが持っていることを意味するものではありません。 –

関連する問題