Cyh的博客

          Email:kissyan4916@163.com
          posts - 26, comments - 19, trackbacks - 0, articles - 220

          導航

          公告

          一直努力努力努力,像奴隸奴隸奴隸!~~
          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          常用鏈接

          隨筆檔案(25)

          文章分類(219)

          文章檔案(220)

          新聞檔案(66)

          相冊

          收藏夾(7)

          最新隨筆

          搜索

          •  

          最新評論

          閱讀排行榜

          網絡編程>>聊天室服務器端

          Posted on 2009-12-18 21:51 啥都寫點 閱讀(755) 評論(0)  編輯  收藏 所屬分類: J2SE

            聊天室的服務器端主要用于接收客戶端的連接與斷開請求、廣播聊天室的成員信息、將成員的聊天信息公布給所有成員。
            服務器端在某個端口上開啟ServerSocket,接收客戶端的連接請求。根據客戶端的IP地址和賬號,判斷客戶端是否重復登錄,如果不是,便允許它加入聊天室,并將最新的成員列表發送給所有客戶端。
            每當收到客戶端的聊天信息時,將聊天信息發送給所有客戶端。
            為了處理多個客戶端同時登錄聊天室,采用了多線程的技術,對于每個客戶端,都用一個線程專門處理它。


          /**------------------------------------------------------ChatServer.java--------------------------------------------------------------------*/

          import java.awt.BorderLayout;
          import java.awt.Color;
          import java.awt.event.ActionEvent;
          import java.awt.event.ActionListener;
          import java.awt.event.WindowEvent;
          import java.io.BufferedReader;
          import java.io.IOException;
          import java.io.InputStreamReader;
          import java.io.PrintStream;
          import java.net.ServerSocket;
          import java.net.Socket;
          import java.util.StringTokenizer;
          import java.util.Vector;

          import javax.swing.BorderFactory;
          import javax.swing.JFrame;
          import javax.swing.JLabel;
          import javax.swing.JMenu;
          import javax.swing.JMenuBar;
          import javax.swing.JMenuItem;
          import javax.swing.JPanel;
          import javax.swing.JScrollPane;
          import javax.swing.SwingUtilities;
          import javax.swing.UIManager;
          import javax.swing.border.TitledBorder;

          /**
           * 聊天室的服務器端程序,GUI界面
           
          */

          public class ChatServer extends JFrame {

              
          // 狀態欄標簽
              static JLabel statusBar = new JLabel();
              
          // 顯示客戶端的連接信息的列表
              static java.awt.List connectInfoList = new java.awt.List(10);

              
          // 保存當前處理客戶端請求的處理器線程
              static Vector clientProcessors = new Vector(10);
              
          // 當前的連接數
              static int activeConnects = 0;

              
          // 構造方法
              public ChatServer()    {
                  init();
                  
          try {
                      
          // 設置界面為系統默認外觀
                      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                      SwingUtilities.updateComponentTreeUI(
          this);
                  }
           catch (Exception e) {
                      e.printStackTrace();
                  }

              }


              
          private void init(){

                  
          this.setTitle("聊天室服務器");
                  statusBar.setText(
          "");

                  
          // 初始化菜單
                  JMenu fileMenu = new JMenu();
                  fileMenu.setText(
          "文件");
                  JMenuItem exitMenuItem 
          = new JMenuItem();
                  exitMenuItem.setText(
          "退出");
                  exitMenuItem.addActionListener(
          new ActionListener() {
                      
          public void actionPerformed(ActionEvent e) {
                          exitActionPerformed(e);
                      }

                  }
          );
                  fileMenu.add(exitMenuItem);
                  
                  JMenuBar menuBar 
          = new JMenuBar();
                  menuBar.add(fileMenu);
                  
          this.setJMenuBar(menuBar);

                  
          // 將組件進行布局
                  JPanel jPanel1 = new JPanel();
                  jPanel1.setLayout(
          new BorderLayout());
                  JScrollPane pane 
          = new JScrollPane(connectInfoList);
                  pane.setBorder(
          new TitledBorder(BorderFactory.createEtchedBorder(
                          Color.white, 
          new Color(134134134)), "客戶端連接信息"));
                  jPanel1.add(
          new JScrollPane(pane), BorderLayout.CENTER);
                  
                  
          this.getContentPane().setLayout(new BorderLayout());
                  
          this.getContentPane().add(statusBar, BorderLayout.SOUTH);
                  
          this.getContentPane().add(jPanel1, BorderLayout.CENTER);

                  
          this.pack();
              }


              
          /**
               * 退出菜單項事件
               * 
          @param e
               
          */

              
          public void exitActionPerformed(ActionEvent e){
                  
          //    向客戶端發送斷開連接信息
                  sendMsgToClients(new StringBuffer(Constants.QUIT_IDENTIFER)); 
                  
          // 關閉所有的連接
                  closeAll(); 
                  System.exit(
          0);
              }


              
          /**
               * 處理窗口關閉事件
               
          */

              
          protected void processWindowEvent(WindowEvent e) {
                  
          super.processWindowEvent(e);
                  
          if (e.getID() == WindowEvent.WINDOW_CLOSING) {
                      exitActionPerformed(
          null);
                  }

              }


              
          /**
               * 刷新聊天室,不斷刷新clientProcessors,制造最新的用戶列表
               
          */

              
          public static void notifyRoomPeople(){
                  StringBuffer people 
          = new StringBuffer(Constants.PEOPLE_IDENTIFER);
                  
          for (int i = 0; i < clientProcessors.size(); i++{
                      ClientProcessor c 
          = (ClientProcessor) clientProcessors.elementAt(i);
                      people.append(Constants.SEPERATOR).append(c.clientName);
                  }

                  
          //    用sendClients方法向客戶端發送用戶列表的信息
                  sendMsgToClients(people); 
              }


              
          /**
               * 向所有客戶端群發消息
               * 
          @param msg
               
          */

              
          public static synchronized void sendMsgToClients(StringBuffer msg) {
                  
          for (int i = 0; i < clientProcessors.size(); i++{
                      ClientProcessor c 
          = (ClientProcessor) clientProcessors.elementAt(i);
                      System.out.println(
          "send msg: " + msg);
                      c.send(msg);
                  }

              }


              
          /**
               * 關閉所有連接
               
          */

              
          public static void closeAll(){
                  
          while (clientProcessors.size() > 0)    {
                      ClientProcessor c 
          = (ClientProcessor) clientProcessors.firstElement();
                      
          try {
                          
          // 關閉socket連接和處理線程
                          c.socket.close();
                          c.toStop();
                      }
           catch (IOException e) {
                          System.out.println(
          "Error:" + e);
                      }
           finally {
                          clientProcessors.removeElement(c);
                      }

                  }

              }


              
          /**
               * 判斷客戶端是否合法。
               * 不允許同一客戶端重復登陸,所謂同一客戶端是指IP和名字都相同。
               * 
          @param newclient
               * 
          @return
               
          */

              
          public static boolean checkClient(ClientProcessor newclient){
                  
          if (clientProcessors.contains(newclient)){
                      
          return false;
                  }
           else {
                      
          return true;
                  }

              }


              
          /**
               * 斷開某個連接,并且從連接列表中刪除
               * 
          @param client
               
          */

              
          public static void disconnect(ClientProcessor client){
                  disconnect(client, 
          true);
              }

              
              
          /**
               * 斷開某個連接,根據要求決定是否從連接列表中刪除
               * 
          @param client
               * 
          @param toRemoveFromList
               
          */

              
          public static synchronized void disconnect(ClientProcessor client, boolean toRemoveFromList){
                  
          try {
                       
          //在服務器端程序的list框中顯示斷開信息
                      connectInfoList.add(client.clientIP + "斷開連接");

                      ChatServer.activeConnects
          --//將連接數減1
                      String constr = "目前有" + ChatServer.activeConnects + "客戶相連";
                      statusBar.setText(constr);
                      
          //向客戶發送斷開連接信息
                      client.send(new StringBuffer(Constants.QUIT_IDENTIFER)); 
                      client.socket.close();

                  }
           catch (IOException e) {
                      System.out.println(
          "Error:" + e);
                  }
           finally {
                      
          //從clients數組中刪除此客戶的相關socket等信息, 并停止線程。
                      if (toRemoveFromList) {
                          clientProcessors.removeElement(client);
                          client.toStop();
                      }

                  }

              }

              
              
          public static void main(String[] args) {

                  ChatServer chatServer1 
          = new ChatServer();
                  chatServer1.setVisible(
          true);
                  System.out.println(
          "Server starting ");

                  ServerSocket server 
          = null;
                  
          try {
                      
          // 服務器端開始偵聽
                      server = new ServerSocket(Constants.SERVER_PORT);
                  }
           catch (IOException e) {
                      System.out.println(
          "Error:" + e);
                      System.exit(
          1);
                  }

                  
          while (true{
                      
          // 如果當前客戶端數小于MAX_CLIENT個時接受連接請求
                      if (clientProcessors.size() < Constants.MAX_CLIENT) {
                          Socket socket 
          = null;
                          
          try {
                              
          // 收到客戶端的請求
                              socket = server.accept();
                              
          if (socket != null{
                                  System.out.println(socket 
          + "連接");
                              }

                          }
           catch (IOException e) {
                              System.out.println(
          "Error:" + e);
                          }


                          
          //    定義并實例化一個ClientProcessor線程類,用于處理客戶端的消息
                          ClientProcessor c = new ClientProcessor(socket);
                          
          if (checkClient(c)) {
                              
          // 添加到列表
                              clientProcessors.addElement(c);
                              
          // 如果客戶端合法,則繼續
                              int connum = ++ChatServer.activeConnects;
                              
          // 在狀態欄里顯示連接數
                              String constr = "目前有" + connum + "客戶相連";
                              ChatServer.statusBar.setText(constr);
                              
          // 將客戶socket信息寫入list框
                              ChatServer.connectInfoList.add(c.clientIP + "連接"); 
                              c.start();
                              
          // 通知所有客戶端用戶列表發生變化
                              notifyRoomPeople();
                          }
           else {
                              
          //如果客戶端不合法
                              c.ps.println("不允許重復登陸");
                              disconnect(c, 
          false);
                          }


                      }
           else {
                          
          //如果客戶端超過了MAX_CLIENT個,則等待一段時間再嘗試接受請求
                          try {
                              Thread.sleep(
          200);
                          }
           catch (InterruptedException e) {
                          }

                      }

                  }

              }

          }


          /**
           * 處理客戶端發送的請求的線程
           
          */

          class ClientProcessor extends Thread {
              
          //存儲一個連接客戶端的socket信息
              Socket socket;
              
          //存儲客戶端的連接姓名
              String clientName;

              
          //存儲客戶端的ip信息
              String clientIP;
              
              
          //用來實現接受從客戶端發來的數據流
              BufferedReader br;
              
          //用來實現向客戶端發送信息的打印流
              PrintStream ps; 

              
          boolean running = true;
              
              
          /**
               * 構造方法
               * 
          @param s
               
          */

              
          public ClientProcessor(Socket s) {
                  socket 
          = s;
                  
          try {
                      
          //    初始化輸入輸出流
                      br = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
                      ps 
          = new PrintStream(socket.getOutputStream()); 
                      
          // 讀取收到的信息,第一條信息是客戶端的名字、IP信息
                      String clientInfo = br.readLine();
                      
                      
          // 讀取信息,根據消息分隔符解析消息
                      StringTokenizer stinfo = new StringTokenizer(clientInfo, Constants.SEPERATOR);
                      String head 
          = stinfo.nextToken(); 
                      
          if (head.equals(Constants.CONNECT_IDENTIFER)){
                          
          if (stinfo.hasMoreTokens()){
                              
          //關鍵字后的第二段數據是客戶名信息
                              clientName = stinfo.nextToken(); 
                          }

                          
          if (stinfo.hasMoreTokens()){
                              
          //關鍵字后的第三段數據是客戶ip信息
                              clientIP = stinfo.nextToken(); 
                          }

                          System.out.println(head); 
          //在控制臺打印頭信息
                      }

                  }
           catch (IOException e) {
                      System.out.println(
          "Error:" + e);
                  }

              }


              
          /**
               * 向客戶端發送消息
               * 
          @param msg
               
          */

              
          public void send(StringBuffer msg)    {
                  ps.println(msg); 
                  ps.flush();
              }

              
              
          //線程運行方法
              public void run() {

                  
          while (running) {
                      String line 
          = null;
                      
          try {
                          
          //讀取客戶端發來的數據流
                          line = br.readLine();

                      }
           catch (IOException e) {
                          System.out.println(
          "Error" + e);
                          ChatServer.disconnect(
          this);
                          ChatServer.notifyRoomPeople();
                          
          return;
                      }

                       
          //客戶已離開
                      if (line == null){
                          ChatServer.disconnect(
          this);
                          ChatServer.notifyRoomPeople();
                          
          return;
                      }


                      StringTokenizer st 
          = new StringTokenizer(line, Constants.SEPERATOR);
                      String keyword 
          = st.nextToken();

                      
          // 如果關鍵字是MSG則是客戶端發來的聊天信息
                      if (keyword.equals(Constants.MSG_IDENTIFER)){
                          StringBuffer msg 
          = new StringBuffer(Constants.MSG_IDENTIFER).append(Constants.SEPERATOR);
                          msg.append(clientName);
                          msg.append(st.nextToken(
          "\0"));
                          
          //    再將某個客戶發來的聊天信息發送到每個連接客戶的聊天欄中
                          ChatServer.sendMsgToClients(msg); 
                          
                      }
           else if (keyword.equals(Constants.QUIT_IDENTIFER)) {
                          
          //    如果關鍵字是QUIT則是客戶端發來斷開連接的信息
                          
                          
          //    服務器斷開與這個客戶的連接
                          ChatServer.disconnect(this); 
                          
          //    繼續監聽聊天室并刷新其他客戶的聊天人名list
                          ChatServer.notifyRoomPeople(); 
                          running 
          = false;
                      }

                  }

              }

              
              
          public void toStop(){
                  running 
          = false;
              }

              
              
          // 覆蓋Object類的equals方法
              public boolean equals(Object obj){
                  
          if (obj instanceof ClientProcessor){
                      ClientProcessor obj1 
          = (ClientProcessor)obj;
                      
          if (obj1.clientIP.equals(this.clientIP) && 
                              (obj1.clientName.equals(
          this.clientName))){
                          
          return true;
                      }

                  }

                  
          return false;
              }

              
              
          // 覆蓋Object類的hashCode方法
              public int hashCode(){
                  
          return (this.clientIP + Constants.SEPERATOR + this.clientName).hashCode();
              }

          }
           

          /**---------------------------------Constants.java------------------------------------*/
          /**
           * 定義聊天室程序中用到的常量
           
          */

          public class Constants {

              
          // 服務器的端口號
              public static final int SERVER_PORT = 2525;
              
          public static final int MAX_CLIENT = 10;
              
              
          // 消息標識符與消息體之間的分隔符
              public static final String SEPERATOR = "";
              
              
          // 消息信息的標識符
              public static final String MSG_IDENTIFER = "MSG";
              
          // 用戶列表信息的標識符
              public static final String PEOPLE_IDENTIFER = "PEOPLE";
              
          // 連接服務器信息的標識符
              public static final String CONNECT_IDENTIFER = "INFO";
              
          // 退出信息標識符
              public static final String QUIT_IDENTIFER = "QUIT";
              
          }





                                                                                                                 --    學海無涯
                  

          主站蜘蛛池模板: 南昌县| 尉犁县| 定兴县| 长治县| 霍州市| 大邑县| 南汇区| 郑州市| 迁安市| 白城市| 中牟县| 通江县| 寿光市| 黄浦区| 东阿县| 安平县| 饶河县| 武夷山市| 三台县| 永胜县| 简阳市| 德州市| 兴宁市| 普宁市| 崇仁县| 岑巩县| 和龙市| 泽普县| 和平县| 河曲县| 防城港市| 鹿泉市| 芦山县| 临湘市| 伊春市| 满洲里市| 噶尔县| 安义县| 靖江市| 德昌县| 南川市|