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
阅读更多
文章标签: socket 异步 java
个人分类: java
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭