2014-01-21 28 views
0

我一直在建設一個聊天服務器,以瞭解線程和使用套接字。我使用頭第一個Java作爲指導(我仍然困惑了幾件事情,這就是爲什麼我可能有這個問題:D),下面的代碼是我的。java如何獲得一個字符串到服務器(jave.net/sockets)

如果您閱讀我的代碼,您會看到我有客戶端通過單擊「連接」按鈕連接到服務器。當他們這樣做時,彈出一個新的jframe,要求他們的聊天會話的首選名稱。當他們輸入時,它被保存在客戶端代碼中的字符串中。我的問題是,如何將這個名稱傳遞給服務器,並使其每次客戶端發送消息時都將其名稱顯示在消息之前?

謝謝你的幫助!

(同樣,如果有誰知道一個很好的鏈接,可以解釋插座和插座/客戶端交互,通過螺紋是如何發生的,這將是偉大的!)

服務器代碼:

import java.io.*; 
import java.net.*; 
import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import java.util.*; 


public class GameServerOne { 
    ArrayList clientOutputStreams; 
    String clientName; 
    private class ClientThreadHandler implements Runnable { 
     BufferedReader clientIncomingReader; 
     Socket socket1; 
     public ClientThreadHandler(Socket clientSocket2) { 
      try { 
       socket1 = clientSocket2; 
       InputStreamReader clientInputReader = new InputStreamReader(socket1.getInputStream()); 
       clientIncomingReader = new BufferedReader(clientInputReader); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
     public void run() { 
      String message; 
      try { 
       while ((message = clientIncomingReader.readLine()) != null) { 
        tellEveryone(message); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
    public void tellEveryone(String message) { 
     Iterator it = clientOutputStreams.iterator(); 
     while(it.hasNext()) { 
      try { 
       PrintWriter writer = (PrintWriter) it.next(); 
       writer.println(message); 
       writer.flush(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    public void setUpServer() { 
     clientOutputStreams = new ArrayList(); 
     try { 
      ServerSocket gameSocket = new ServerSocket(5151); 
      //System.out.println("Server Connected"); 

      while (true) { 
       Socket clientSocket = gameSocket.accept(); 
       PrintWriter writer = new PrintWriter(clientSocket.getOutputStream()); 
       writer.println("User connected"); 
       writer.flush(); 
       clientOutputStreams.add(writer); 
       Thread t = new Thread(new ClientThreadHandler(clientSocket)); 
       t.start(); 


      } 

     } catch (Exception ex) { 
       ex.printStackTrace(); 
     } 
    } 
    public static void main(String[] args) { 
     new GameServerOne().setUpServer(); 
    } 


} 

客戶端代碼:

import java.io.*; 
import java.net.*; 
import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 


public class GameClientOne { 
    Socket gameSocket; 
    JFrame inputNameFrame; 
    JFrame clientFrame; 
    JTextArea chatArea; 
    JTextField messageInput; 
    BufferedReader gameChatReader; 
    PrintWriter gameChatWriter; 
    JTextField nameField; 
    boolean sessionNamePicked = false; 
    String userSessionName; 
    BufferedReader gameBufferedReader; 



    public GameClientOne() { 
     setUpGUI(); 
    } 

    public void setUpGUI() { 
     clientFrame = new JFrame("Game Window"); 
     JPanel mainPanel = new JPanel(new BorderLayout()); 
     JPanel southPanel = new JPanel(new BorderLayout()); 
     JPanel centerPanel = new JPanel(new BorderLayout()); 
     chatArea = new JTextArea(); 
     chatArea.setWrapStyleWord(true); 
     chatArea.setLineWrap(true); 
     chatArea.setEditable(false); 
     JScrollPane chatScroller = new JScrollPane(chatArea); 
     messageInput = new JTextField(); 
     messageInput.addKeyListener(new MessageInputFieldListener()); 
     JButton sendButton = new JButton("Send"); 
     sendButton.addActionListener(new SendButtonListener()); 
     JPanel westPanel = new JPanel(/*new GridLayout(20, 1)*/); 
     JPanel eastPanel = new JPanel(); 
     JButton connectButton = new JButton("Connect"); 
     connectButton.addActionListener(new ConnectButtonListener()); 
     connectButton.setPreferredSize(new Dimension(100, 28)); 
     JPanel northPanel = new JPanel(new FlowLayout()); 
     JLabel northTitleLabel = new JLabel("Game Screen"); 
     westPanel.add(connectButton); 
     chatScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS) ; 
     chatScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 



     northPanel.add(northTitleLabel); 
     centerPanel.add(BorderLayout.CENTER, chatScroller); 
     southPanel.add(BorderLayout.CENTER, messageInput); 
     southPanel.add(BorderLayout.EAST, sendButton); 
     mainPanel.add(BorderLayout.SOUTH, southPanel); 
     mainPanel.add(BorderLayout.CENTER, centerPanel); 
     mainPanel.add(BorderLayout.WEST, westPanel); 
     mainPanel.add(BorderLayout.EAST, eastPanel); 
     mainPanel.add(BorderLayout.NORTH, northPanel); 

     clientFrame.add(mainPanel); 
     clientFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     clientFrame.setSize(450, 600); 
     clientFrame.setVisible(true); 
     messageInput.requestFocusInWindow(); 

    } 
    public void setUpInputNameFrame() { 
     inputNameFrame = new JFrame("Insert Name"); 
     JPanel mainPanel = new JPanel(new BorderLayout()); 
     nameField = new JTextField(); 
     nameField.addKeyListener(new NameFieldListener()); 
     JButton submitButton = new JButton("Submit"); 
     submitButton.addActionListener(new SubmitButtonListener()); 
     JLabel inputNameLabel = new JLabel("Please pick a name for the chat session"); 
     JPanel northPanel = new JPanel(new FlowLayout()); 
     JPanel southPanel = new JPanel(new BorderLayout()); 
     northPanel.add(inputNameLabel); 
     southPanel.add(BorderLayout.CENTER, nameField); 
     southPanel.add(BorderLayout.EAST, submitButton); 
     mainPanel.add(BorderLayout.NORTH, northPanel); 
     mainPanel.add(BorderLayout.SOUTH, southPanel); 
     inputNameFrame.add(mainPanel); 
     inputNameFrame.setSize(300, 150); 
     inputNameFrame.setVisible(true); 
     nameField.requestFocusInWindow(); 
    } 

    public void connectToGameServer() { 
      try { 

       gameSocket = new Socket("127.0.0.1", 5151); 
       InputStreamReader gameSocketReader = new InputStreamReader(gameSocket.getInputStream()); 
       gameBufferedReader = new BufferedReader(gameSocketReader); 
       gameChatWriter = new PrintWriter(gameSocket.getOutputStream()); 
       chatArea.append("Connected with name: " + userSessionName + "\n"); 
       Thread incomingTextThread = new Thread(new IncomingTextReader()); 
       incomingTextThread.start(); 
       //System.out.println("Connected to Game"); 
      } catch (Exception e) { 
       System.out.println("Could not connect to game..."); 
       e.printStackTrace(); 
      } 

    } 

    //ALL LISTENER CLASSES BELOW HERE 
    //main chat page listeners 
    private class ConnectButtonListener implements ActionListener { 
     public void actionPerformed(ActionEvent e) { 
      if (!sessionNamePicked) { 
       setUpInputNameFrame(); 
      } else { 
       chatArea.append("You already connected!\n"); 
      } 


     } 
    } 
    private class SendButtonListener implements ActionListener { 
     public void actionPerformed(ActionEvent e) { 
      if (!sessionNamePicked) { 
       chatArea.append("Please connect first\n"); 
       messageInput.setText(""); 
       messageInput.requestFocusInWindow(); 
      } else { 
       try { 
        gameChatWriter.println(messageInput.getText()); 
        gameChatWriter.flush(); 
       } catch (Exception ex2) { 
        ex2.printStackTrace(); 
       } 
       //chatArea.append(userSessionName + ": " + messageInput.getText() + "\n"); 
       messageInput.setText(""); 
       messageInput.requestFocusInWindow(); 
      } 
     } 
    } 
    private class MessageInputFieldListener implements KeyListener { 
     public void keyPressed(KeyEvent e) { 

     } 
     public void keyTyped(KeyEvent e) { 

     } 
     public void keyReleased(KeyEvent e) { 
      if (e.getKeyCode() == KeyEvent.VK_ENTER) { 
       if (!sessionNamePicked) { 
        chatArea.append("Please connect first\n"); 
        messageInput.setText(""); 
       } else { 
        try { 
         gameChatWriter.println(messageInput.getText()); 
         gameChatWriter.flush(); 
        } catch (Exception ex2) { 
         ex2.printStackTrace(); 
        } 
        //chatArea.append(userSessionName + ": " + messageInput.getText() + "\n"); 
        messageInput.setText(""); 
       } 
      } 
     } 
    } 

    //pick chat session name listeners: nameField/submitButton 
    private class NameFieldListener implements KeyListener { 
     public void keyPressed(KeyEvent e) { 

     } 
     public void keyTyped(KeyEvent e) { 

     } 
     public void keyReleased(KeyEvent e) { 
       if (!nameField.getText().isEmpty() && e.getKeyCode() == KeyEvent.VK_ENTER) { 
        userSessionName = nameField.getText(); 
        sessionNamePicked = true; 
        connectToGameServer(); 
        inputNameFrame.dispose(); 
        messageInput.requestFocusInWindow(); 
       } 

     } 
    } 
    private class SubmitButtonListener implements ActionListener { 
     public void actionPerformed (ActionEvent e) { 
      if (!nameField.getText().isEmpty()) { 
       userSessionName = nameField.getText(); 
       sessionNamePicked = true; 
       connectToGameServer(); 
       inputNameFrame.dispose(); 
       messageInput.requestFocusInWindow(); 
      } 
     } 
    } 
    //Runnable implementation for threads 
    private class IncomingTextReader implements Runnable { 
     public void run() { 
      String incomingMessage; 
      try { 
       while ((incomingMessage = gameBufferedReader.readLine()) != null) { 
        chatArea.append(incomingMessage + "\n"); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    } 


    public static void main(String[] args) { 
     GameClientOne gameClient = new GameClientOne(); 
    } 


} 
+0

請參閱示例[此處](http://stackoverflow.com/a/3245805/230513)和[這裏](http://stackoverflow.com/a/14617650/230513)。 – trashgod

+0

謝謝,我現在看看:) –

回答

1

如果你想發送不僅僅是一個你現在的樣子消息的更多,你將需要一個協議來決定如何處理收到的字符串來執行,而不是隻需S結束它給所有其他客戶端。

例如,在客戶端發送客戶端名稱,您可能會編寫NAME :(客戶端名稱),然後在服務器上將字符串拆分爲:並檢查第一部分是否爲NAME,以及如果所以請將客戶端名稱設置爲字符串的其餘部分。你應該考慮你可能想發送的其他類型的數據,並設計一個適用於它的協議。

下面是如何做到上面的例子:

在客戶端,您可以添加行gameChatWriter.write("NAME:"+name)(創建的名頭,當然)的連接後imediatly。然後在服務器上,而不是調用tellEveryone(message)當消息被收到創建一個名爲processInput方法,並調用它,這可能是這樣的:

private void processInput(String message){ 
    String[] commands=message.split(':'); 
    if(commands[0].equals("NAME")){ 
     clientName=commands[1]; 
    } 
    else{ 
     tellEveryone(message); 
    } 
} 

現在你只有一個String clientName,你顯然需要更多的您希望與其他客戶交談,所以我建議將線程處理程序變成一個單獨的類,您將爲每個客戶端實例化並可以持有類似的東西。

當你完成這個工作之後,你還可以創建一個獨立的方法來編寫你想要發送給客戶端或服務器的其他東西以及在客戶端處理輸入的方法。希望這可以幫助。

+0

謝謝你的回答,我會嘗試你的建議! –

+0

如果你不介意我困擾你一分鐘,你能否給我一個如何做這個協議的簡單例子。我是一個新手,需要一些幫助 –