特简单, 没有数据库, 还没有处理各种异常。
登录:输入用户名点击的登录即可。
发送消息: 特定格式->toUser:message
1. 服务器:保存在线用户
public class Online { private static Online mOnline = null; private LinkedHashMap<String, Socket> mOnlines = new LinkedHashMap<String, Socket>(); private Online() { } public synchronized static Online getInstance() { if(null == mOnline) { mOnline = new Online(); } return mOnline; } public void put(String key, Socket socket) { if(!mOnlines.containsKey(key)) { mOnlines.put(key, socket); } } public Socket get(String key) { return mOnlines.get(key); } public void remove(String key) { mOnlines.remove(key); }}
2. 服务器:一个简单的socket服务器
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket; // login:uid// send:fromuser:touser:message// logout:uidpublic class Server implements Runnable { private Socket mSocket; private Online mOnline; public Server(Socket socket) { mSocket = socket; mOnline = Online.getInstance(); } @Override public void run() { try { BufferedReader reader = new BufferedReader(new InputStreamReader( mSocket.getInputStream())); String cmd = reader.readLine(); // login if (cmd.startsWith("login")) { String userName = cmd.split(":")[1]; mOnline.put(userName, mSocket); System.out.println(userName + " login..."); PrintWriter writer = new PrintWriter(mSocket.getOutputStream()); writer.println("success"); writer.flush(); } else if (cmd.startsWith("send")) { System.out.println(cmd); String[] cmds = cmd.split(":"); String from = cmds[1]; Socket to = mOnline.get(cmds[2]); String msg = cmds[3]; PrintWriter writer = new PrintWriter(to.getOutputStream()); System.out.println("rec:" + from + ":" + cmds[2] + ":" + msg); writer.println("rec:" + from + ":" + cmds[2] + ":" + msg); writer.flush(); }else if (cmd.startsWith("logout")) { System.out.println(cmd); String user = cmd.split(":")[1]; mOnline.get(user).close(); mOnline.remove(user); PrintWriter writer = new PrintWriter(mSocket.getOutputStream()); writer.println("success"); writer.flush(); } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception { ServerSocket server = new ServerSocket(8888); boolean flag = true; while (flag) { new Thread(new Server(server.accept())).start(); System.out.println("user in..."); } server.close(); }}
3. 客户端登录界面
public class MainActivity extends Activity { private EditText mUser; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mUser = (EditText) findViewById(R.id.username); } public void login(View view) { final String userName = mUser.getText().toString().trim(); Login login = new Login(userName); login.setOnLoginListener(new Login.LoginCallback() { @Override public void onLogin(boolean success) { if(success) { Intent intent = new Intent(MainActivity.this, Chat.class); intent.putExtra("user", userName); startActivity(intent); finish(); }else { Toast.makeText(MainActivity.this, "登录失败", Toast.LENGTH_SHORT).show(); } } }); login.login(); }}
4. 处理登录
public class Login { private String mUserName; private LoginCallback mCallback; public Login(String userName) { mUserName = userName; } public void setOnLoginListener(LoginCallback callback) { mCallback = callback; } private Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case Constant.SUCCESS: mCallback.onLogin(true); break; case Constant.FAILED: mCallback.onLogin(false); break; } }; }; public void login() { new Thread(new Runnable() { @Override public void run() { Socket socket = null; try { socket = new Socket(); socket.connect(new InetSocketAddress("192.168.100.100", 8888), 4000); PrintWriter writer = new PrintWriter(socket.getOutputStream()); writer.println("login:" + mUserName); writer.flush(); BufferedReader reader = new BufferedReader( new InputStreamReader(socket.getInputStream())); String line = reader.readLine(); System.out.println(line); if("success".equals(line)) { PConnection.socket = socket; mHandler.sendEmptyMessage(Constant.SUCCESS); }else { mHandler.sendEmptyMessage(Constant.FAILED); } }catch(Exception e) { e.printStackTrace(); } } }).start(); } public interface LoginCallback { public void onLogin(boolean success); }}
5. 聊天界面
public class Chat extends Activity { private String mUserName; private EditText mEdit; private ListView mMessage; private ReceiverMessage mRecMessage; private SendMessage mSendMesage; private List<Map<String, String>> mData = new ArrayList<Map<String, String>>(); private MessagesAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.chat_layout); mUserName = getIntent().getStringExtra("user"); mEdit = (EditText) findViewById(R.id.edit); mMessage = (ListView) findViewById(R.id.message); mRecMessage = new ReceiverMessage(); mRecMessage.setOnReceiverListener(new RecListener()); mRecMessage.run(); mSendMesage = new SendMessage(); mSendMesage.setOnSendListener(new SendListener()); mAdapter = new MessagesAdapter(this, mData); mMessage.setAdapter(mAdapter); } public void send(View view) { String[] content = mEdit.getText().toString().trim().split(":"); mSendMesage.send(mUserName, content[0], content[1]); } private class RecListener implements ReceiverMessage.OnReceiverListener { @Override public void onReceiver(String user, String msg) { Map<String, String> temp = new HashMap<String, String>(); temp.put("user", user); temp.put("msg", msg); temp.put("pos", "right"); mData.add(temp); mAdapter.notifyDataSetChanged(); } } private class SendListener implements SendMessage.OnSendListener { @Override public void onSend(String[] msg) { Map<String, String> temp = new HashMap<String, String>(); temp.put("user", "我"); temp.put("msg", msg[1]); temp.put("pos", "left"); mData.add(temp); mAdapter.notifyDataSetChanged(); } } @Override public boolean onOptionsItemSelected(MenuItem item) { if(R.id.logout == item.getItemId()) { Logout logout = new Logout(); logout.setOnLogoutListener(new Logout.OnLogoutListener() { @Override public void onLogout(boolean success) { if(success) { Toast.makeText(Chat.this, "注销成功", Toast.LENGTH_SHORT).show(); finish(); }else { Toast.makeText(Chat.this, "注销失败", Toast.LENGTH_SHORT).show(); } } }); logout.logout(mUserName); } return super.onOptionsItemSelected(item); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return super.onCreateOptionsMenu(menu); }}
6. 发送消息
public class SendMessage { private OnSendListener mListener; public void setOnSendListener(OnSendListener listener) { mListener = listener; } private Handler mHandler = new Handler() { public void handleMessage(Message msg) { mListener.onSend((String[]) msg.obj); }; }; // send:from:to:message public void send(final String from , final String to, final String msg) { new Thread(new Runnable() { @Override public void run() { Socket socket = null; try { socket = new Socket(); socket.connect(new InetSocketAddress("192.168.100.100", 8888), 4000); PrintWriter writer = new PrintWriter(socket.getOutputStream()); writer.println("send:" + from + ":" + to + ":" + msg); writer.flush(); Message message = mHandler.obtainMessage( Constant.SUCCESS, new String[] {to, msg}); message.sendToTarget(); } catch(Exception e) { } finally { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }).start(); } public interface OnSendListener { public void onSend(String[] msg); }}
7. 接收消息,死循环,但阻塞,没啥问题
public class ReceiverMessage { private OnReceiverListener mListener; public void setOnReceiverListener(OnReceiverListener listener) { mListener = listener; } private Handler mHandler = new Handler() { public void handleMessage(Message msg) { String[] cmds = (String[]) msg.obj; mListener.onReceiver(cmds[0], cmds[1]); }; }; public void run() { new Thread(new Runnable() { @Override public void run() { try { Socket socket = PConnection.socket; while(true) { System.out.println("wait for message..."); BufferedReader reader = new BufferedReader( new InputStreamReader(socket.getInputStream())); String line = reader.readLine(); if(line.startsWith("rec")) { //rec:fromuser:touser:message String[] cmds = line.split(":"); System.out.println(cmds[0] + ":" + cmds[1] + ":" + cmds[2] + ":" + cmds[3]); Message msg = mHandler.obtainMessage(Constant.SUCCESS, new String[] {cmds[1], cmds[3]}); msg.sendToTarget(); } } } catch (Exception e) { e.printStackTrace(); } } }).start(); } public interface OnReceiverListener { public void onReceiver(String user, String msg); }}
8. 注销登录
public class Logout { public OnLogoutListener mListener; public void setOnLogoutListener(OnLogoutListener listner) { mListener = listner; } private Handler mHandler = new Handler() { public void handleMessage(Message msg) { if(Constant.SUCCESS == msg.what) { mListener.onLogout(true); }else { mListener.onLogout(false); } }; }; public void logout(final String user) { new Thread(new Runnable() { @Override public void run() { try { Socket socket = new Socket(); socket.connect(new InetSocketAddress("192.168.100.100", 8888), 4000); PrintWriter writer = new PrintWriter(socket.getOutputStream()); writer.println("logout:" + user); writer.flush(); BufferedReader reader = new BufferedReader( new InputStreamReader(socket.getInputStream())); if("success".equals(reader.readLine())) { PConnection.socket = null; mHandler.sendEmptyMessage(Constant.SUCCESS); }else { mHandler.sendEmptyMessage(Constant.FAILED); } } catch (Exception e) { e.printStackTrace(); } } }).start(); } public interface OnLogoutListener { public void onLogout(boolean success); }}
9. 存放登录后的socket,在发送消息和接收消息时使用该socket
public class PConnection { public static Socket socket;}
希望本文所述对大家学习有所帮助。