本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