Java小程序之簡單多人聊天室的實現(山寨QQ前傳)

duzicunhuo 9年前發布 | 21K 次閱讀 Java Java開發

一、前言:

通過對Java服務器生猛上手的學習,已經基本明白了Java中通信的基本原理,以及服務器,ip,ip地址的概念;

我們思考下服務器到底是用來干嘛的呢?當多臺客戶端連上服務器以后,服務器需要提供的就是為連接進來的客戶端提供相應的服務;具體的來說就是處理不同客戶端發來的消息或者數據,然后把這些消息或者數據發送到另外的客戶端;服務器的目的就是正確轉發消息或者數據;

二、簡單多人聊天室的實現思路:

1、創建服務器, 等待客戶端的連接

2、客戶端連接進來以后,獲取輸入輸出流,利用輸入輸出流發送消息;

3、發送服務器連接成功的信息給客戶端,并提示客戶端輸入賬戶和密碼進行登錄

4、服務器接收客戶端發來的賬號和密碼,校驗成功后,提示登錄成功,開始多人聊天

難點:如何實現多人聊天? 定義一個容器:用于封裝所有的 ServerThread 線程對象,遍歷該容器中的對象,將消息轉發給每一個客戶端(自己可以除外)

問題: 當某個客戶端退出后,其他客戶端再發消息的時候,轉發就會報錯;

解決:當有客戶端退出時,將該客戶端從容器中移除;不在向該客戶端轉發消息;

三、 程序源代碼:

連接服務器類:

package com.huaxin.server;

import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList;

public class Myserver {

public static ArrayList<ServerThread>list =new ArrayList<ServerThread>();

public  void initServer() {

    try {
        //創建服務器對象,并指定端口號
        ServerSocket server = new ServerSocket(9090);
        System.out.println("服務器已經建立......");
        //不斷獲取客戶端的連接
        while(true){
            Socket socket =server.accept();
            System.out.println("客戶端連接進來了......");
            //當有客戶端連接進來以后,開啟一個線程,用來處理該客戶端的邏輯,
            ServerThread st = new ServerThread(socket);
            st.start();
            //添加該客戶端到容器中
            list.add(st);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

}

}</pre>

服務器線程處理類:

package com.huaxin.server;

import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket;

public class ServerThread extends Thread {

public Socket socket;
public InputStream ins;
public OutputStream ous;

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

public void run() {
    try {
        // 獲取輸入輸出流
        ins = socket.getInputStream();
        ous = socket.getOutputStream();
        // 發送消息給客戶端
        String msg = "welcome to zhou's server !";
        sendMsg(ous, msg);
        // 發送要求登錄信息給客戶端
        String userinfo = "please input your name:";
        sendMsg(ous, userinfo);
        // 獲取客戶端輸入的用戶名
        String userName = readMsg(ins);
        // 發送要求密碼信息給客戶端
        String pwd = "please input your password:";
        sendMsg(ous,  pwd);
        // 獲取客戶端輸入的密碼
        String pass = readMsg(ins);
        // 登錄驗證
        boolean falg = loginCheck(userName, pass);
        // 校驗不通過時,循環校驗
        while (!falg) {
            msg = "Fail to connect server......";
            sendMsg(ous, msg);
            msg = "please check your name and password and login again.....";
            sendMsg(ous, msg);
            msg = "please input your name:";
            sendMsg(ous, msg);
            // 獲取客戶端輸入的用戶名
            userName = readMsg(ins);
            // 發送要求密碼信息給客戶端
            msg = "please input your password:";
            sendMsg(ous, msg);
            // 獲取客戶端輸入的密碼
            pass = readMsg(ins);
            falg = loginCheck(userName, pass);
        }

        // 校驗成功后:開始聊天
        msg = "successful connected..... you can chat with your friends now ......";
        sendMsg(ous, msg);
        // 聊天處理邏輯
        //讀取客戶端發來的消息
        msg=readMsg(ins);
        //輸入bye結束聊天
        while(!"bye".equals(msg)){
            //給容器中的每個對象轉發消息
            for (int i = 0; i <Myserver.list.size(); i++) {
                ServerThread st =Myserver.list.get(i);
                //不該自己轉發消息
                if(st!=this){
                    sendMsg(st.ous, userName+"  is say:"+msg);
                }
            }
            //等待讀取下一次的消息
            msg=readMsg(ins);
        }

    } catch (Exception e) {
        System.out.println("客戶端不正常關閉......");

// e.printStackTrace(); } //有異常后統一將流關閉 try { ins.close(); ous.close(); socket.close(); //將當前已經關閉的客戶端從容器中移除 Myserver.list.remove(this); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }

// 校驗客戶端輸入的賬號和密碼的函數,由于沒有數據庫,暫時寫死了
public boolean loginCheck(String name, String pwd) {
    if (name.equals("zhou") && pwd.equals("zhou") || name.equals("user") && pwd.equals("pwd")
            || name.equals("huaxinjiaoyu") && pwd.equals("huaxinjiaoyu")) {

        return true;
    }
    return false;
}

// 發送消息的函數
public void sendMsg(OutputStream os, String s) throws IOException {
    // 向客戶端輸出信息
    byte[] bytes = s.getBytes();
    os.write(bytes);
    os.write(13);
    os.write(10);
    os.flush();

}

// 讀取客戶端輸入數據的函數
public String readMsg(InputStream ins) throws Exception {
    // 讀取客戶端的信息
    int value = ins.read();
    // 讀取整行 讀取到回車(13)換行(10)時停止讀
    String str = "";
    while (value != 10) {
        // 點擊關閉客戶端時會返回-1值
        if (value == -1) {
            throw new Exception();
        }
        str = str + ((char) value);
        value = ins.read();
    }
    str = str.trim();
    return str;
}

}</pre>

函數入口類:

package com.huaxin.server;

public class Test {

public static void main(String[] args) {
    Myserver ms = new Myserver();
    ms.initServer();
}

}</pre>

四、運行結果:(務必先啟動服務器)

第一次錯誤是由于未先開啟服務器:

輸入正確的用戶名和密碼進行登錄:

聊天界面:(中間有一次密碼輸入錯誤,但是還是可以再次輸入.......)

五、總結:

通過完成這個簡單的多人聊天的小程序,有一種說不出來的喜悅感;原來用Java來實現簡單的多人聊天這么簡單;自己也能寫出一個小小的聊天的軟件了呢......

接下來我們是不是可以寫個山寨版的QQ了呢......哈哈........拭目以待.......

 

來自:http://blog.csdn.net/bluesky_usc/article/details/54318498

 

 本文由用戶 duzicunhuo 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!