java server 多client異步socket通信demo

本demo打包下載,請點擊這裏


本demo主要用java實現了服務器監聽多客戶端登錄,並實現了客戶端與服務器的異步socket通信,通信過程採用了消息隊列緩衝機制(生產者消費者模式)。

登錄過程是後來寫的,用的是同步模式。密碼驗證採用的是和用戶名相同爲驗證pass,可以根據需要修改。

登錄3次失敗後,服務器會斷開該客戶端的socket,客戶端退出,需重新啓動客戶端。

登錄成功後,客戶端需要記住自己的id,這塊忘寫了。可以由服務器返回id,也可以輸入id時記錄(同一個地方輸入,注意不要把密碼當成id記錄了)。

沒有寫客戶端之間的通信,可以使用MsgPacket將發送和接收客戶端id打包發給服務端,在服務端解包後,通過map和id找到接收客戶端的socket,將信息發送過去。

本demo服務端可以向所有客戶端發送推送消息。

本demo是在ubuntu環境下寫的,用javac java命令即可編譯運行。

打包資源裏面有makefile,通過執行make可以編譯,make runs 可以運行服務端,make runc 可以運行客戶端。

沒有心跳機制,可以參考 http://my.oschina.net/fengcunhan/blog/178155


下面是關鍵的代碼。

SocketUtil.java 通信過程中的socket管理,採用了消息隊列機制,並開啓了Sender和Receiver兩個線程處理髮送和接收消息。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class SocketUtil {
    public static final String MSG_QUIT = "quit";

    private Socket mSocket;
    private MsgQueue<String> mMsgQueue = new MsgQueue<String>();

    public SocketUtil(Socket socket) {
        mSocket = socket;
        new Thread(new Sender(), "Sender").start();
        new Thread(new Receiver(), "Receiver").start();
    }

    private class MsgQueue<T> {
        private static final int CAPACITY = 10;
        private List<T> mMsgs = new ArrayList<T>();

        public synchronized void push(T msg) {
            try {
                while (mMsgs.size() >= CAPACITY) {
                    wait();
                }
                mMsgs.add(msg);
                notifyAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public synchronized T pop() {
            T msg = null;
            try {
                while (mMsgs.size() <= 0) {
                    wait();
                }
                msg = mMsgs.get(0);
                mMsgs.remove(0);
                notifyAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return msg;
        }
    }

    private class Sender implements Runnable {
        @Override
        public void run() {
            System.out.println("Sender ... start --- " + Thread.currentThread().getName());
            try {
                PrintWriter out = new PrintWriter(mSocket.getOutputStream(),true);
                String msg = "";
                while (!(msg = mMsgQueue.pop()).equals(MSG_QUIT)) {
                    onMsgSendStart(msg);
                    out.println(msg);
                    onMsgSendEnd(msg, true);
                }
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println("Sender ... end --- " + Thread.currentThread().getName());
        }
    }

    private class Receiver implements Runnable {
        @Override
        public void run() {
            System.out.println("Receiver ... start --- " + Thread.currentThread().getName());
            try {
                BufferedReader in = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
                String msg = "";
                while ((msg = in.readLine()) != null){
                    onMsgReceived(msg);
                }
                in.close();
                pushMsg(MSG_QUIT);//quit sender
                onSocketClosedRemote();
            } catch (IOException e) {
                //e.printStackTrace();
                onSocketClosedSelf();
            }
            System.out.println("Receiver ... end --- " + Thread.currentThread().getName());
        }
    }

    public final void pushMsg(String msg) {
        mMsgQueue.push(msg);
    }

    public final void quit() {
        pushMsg(MSG_QUIT);//quit sender
        try {
            if (mSocket != null) {
                mSocket.close();
                mSocket = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public final Socket getSocket() {
        return mSocket;
    }

    private void onSocketClosedSelf() { }
    protected void onSocketClosedRemote() { }
    protected void onMsgSendStart(String msg) { }
    protected void onMsgSendEnd(String msg, boolean success) { }
    protected void onMsgReceived(String msg) { }
    protected void onMsgInput(String msg) { }
}
MyServer.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.HashMap;
import java.util.Iterator;
import java.util.Map;

public class MyServer {
    private static final int PORT = 9876;
    private static final int MAX_CLIENT_COUNT = Integer.MAX_VALUE;

    private ServerSocket mSS;
    private Map<String, Client> mClients = new HashMap<String, Client>();

    public MyServer() {
        try {
            mSS = new ServerSocket(PORT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void startServer() {
        new Thread(new PushThread(), "PushThread").start();
        try {
            while (mClients.size() < MAX_CLIENT_COUNT) {
                Socket socket = mSS.accept();
                new Thread(new LoginThread(socket), "LoginThread").start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private class LoginThread implements Runnable {
        private static final int MAX_TRY = 3;
        private Socket mSocket;
        public LoginThread(Socket socket) {
            mSocket = socket;
        }

        @Override
        public void run() {
            System.out.println("LoginThread ... start --- " + Thread.currentThread().getName());
            String id = waitForLogin();
            if (id != null) {
                Client client = new Client(mSocket, id);
                mClients.put(id, client);
                System.out.println("A new socket(" + mSocket + ") connected." +
                        " Client size: " + mClients.size());
//                tellAllClientChanged();
            } else {
                try {
                    mSocket.close();
                    mSocket = null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("LoginThread ... end --- " + Thread.currentThread().getName());
        }
        
        private String waitForLogin() {
            String loginId = null;
            try {
                BufferedReader in = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
                PrintWriter out = new PrintWriter(mSocket.getOutputStream(),true);
                for (int i = MAX_TRY; i > 0; i--) {
                    out.println("Login: you can try " + i + " times.");
                    out.println("Please input your id:");
                    String id = in.readLine();
                    if (!isUserExist(id)) {
                        out.println("User (" + id + ") not exist!");
                        continue;
                    }
                    out.println("Please input your password:");
                    String pwd = in.readLine();
                    if (!isPwdCorrect(id, pwd)) {
                        out.println("Password error!");
                        continue;
                    }
                    if (isRepeatLogin(id)) {
                        out.println("User (" + id + ") is already online!");
                        continue;
                    } else {
                        loginId = id;
                        break;
                    }
                }
                //in.close();//do not close here
                if (loginId == null) {
                    out.println("I'm so sorry! Login failed!");
                } else {
                    out.println("Welcome " + loginId + "! Login success!");
                }
            } catch (IOException e) {
                //e.printStackTrace();
            }
            return loginId;
        }
        
        private boolean isUserExist(String id) {
            return true;//TODO
        }
        
        private boolean isPwdCorrect(String id, String pwd) {
            return (id.equals(pwd));//TODO
        }
        
        private boolean isRepeatLogin(String id) {
            return mClients.containsKey(id);
        }
    }

//    private void tellAllClientChanged() {
//        Iterator<String> iterator = mClients.keySet().iterator();
//        while (iterator.hasNext()) {
//            String id = iterator.next();
//            Client client = mClients.get(id);
//            Socket socket = client.getSocket();
//            String ip = socket.getInetAddress().toString();
//            int port = socket.getPort();
//            pushMsgToAllClient("-------------["+id+"]" + ip + ":" + port);
//        }
//    }

    class Client extends SocketUtil {
        private String mId;
        public Client(Socket socket, String id) {
            super(socket);
            mId = id;
        }

        @Override
        protected void onMsgSendStart(String msg) {
            System.out.println("to <" + mId + ">: " + msg);
        }

        @Override
        protected void onMsgReceived(String msg) {
            System.out.println("[" + mId + "]: " + msg);
            pushMsg("Your msg is: " + msg);
        }

        protected void onSocketClosedRemote() {
            mClients.remove(mId);
            System.out.println("Client (" + mId + ") offline. Client size: " + mClients.size());
//            tellAllClientChanged();
        }
    }

    private class PushThread implements Runnable {
        @Override
        public void run() {
            System.out.println("PushThread ... start --- " + Thread.currentThread().getName());
            try {
                BufferedReader sysIn = new BufferedReader(new InputStreamReader(System.in));
                String msg = "";
                while (!(msg = sysIn.readLine()).equals(SocketUtil.MSG_QUIT)) {
                    pushMsgToAllClient(msg);
                }
                sysIn.close();
                closeServer();
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println("PushThread ... end --- " + Thread.currentThread().getName());
        }
    }

    private void pushMsgToAllClient(String msg) {
        Iterator<String> iterator = mClients.keySet().iterator();
        while (iterator.hasNext()) {
            String id = iterator.next();
            Client client = mClients.get(id);
            System.out.println("push message to [" + id + "]" + client);
            client.pushMsg(msg);
        }
    }

    private void closeServer() {
        Iterator<String> iterator = mClients.keySet().iterator();
        while (iterator.hasNext()) {
            String id = iterator.next();
            Client client = mClients.get(id);
            System.out.println("Close [" + id + "]" + client);
            client.quit();
        }
        try {
            mSS.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
MyClient.java

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

public class MyClient {
    private static final String SEVER_IP = "127.0.0.1";
    private static final int SEVER_PORT = 9876;

    private Socket mSocket;
    private ClientSocketUtil mSocketUtil;

    public MyClient() {
        try {
            mSocket = new Socket(SEVER_IP, SEVER_PORT);
            System.out.println("My socket: " + mSocket);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void connect() {
        new Thread(new PushThread(), "PushThread").start();
        mSocketUtil = new ClientSocketUtil(mSocket);
    }

    private class ClientSocketUtil extends SocketUtil {//TODO socket from who to who
        public ClientSocketUtil(Socket socket) {
            super(socket);
        }

        @Override
        protected void onMsgSendStart(String msg) {
            System.out.println("[ME]: " + msg);
        }

        @Override
        protected void onMsgReceived(String msg) {
            System.out.println("[SERVER]: " + msg);
        }

        @Override
        protected void onSocketClosedRemote() {
            socketClosedRemote = true;
            System.out.println("Remote socket closed, input any words to quit.");
        }
    }

    private boolean socketClosedRemote = false;
    private class PushThread implements Runnable {
        @Override
        public void run() {
            System.out.println("PushThread ... start --- " + Thread.currentThread().getName());
            try {
                BufferedReader sysIn = new BufferedReader(new InputStreamReader(System.in));
                String msg = "";
                while (!socketClosedRemote && !(msg = sysIn.readLine()).equals(SocketUtil.MSG_QUIT)) {
                    mSocketUtil.pushMsg(msg);
                }
                sysIn.close();
                mSocketUtil.quit();
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println("PushThread ... end --- " + Thread.currentThread().getName());
        }
    }
}

完整code打包下載:http://download.csdn.net/detail/kingodcool/8747149
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章