Android聊天工具基于socket实现
作者:亓斌哥哥 发布时间:2021-12-06 04:40:01
标签:Android,聊天,socket
特简单, 没有数据库, 还没有处理各种异常。
登录:输入用户名点击的登录即可。
发送消息: 特定格式->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:uid
public 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;
}
希望本文所述对大家学习有所帮助。


猜你喜欢
- 五子棋AI算法也算是一个典型的游戏AI算法,一些棋类的AI算法都可以参考实现,下面是Java实现代码棋盘抽象接口import java.ut
- 简介说明本文用实例介绍stream的使用。JDK8新增了Stream(流操作) 处理集合的数据,可执行查找、过滤和映射数据等操作。使用Str
- 问题我需要从一个java的集合中,根据另一个集合的内容,删除第一个集合中不特定的元素。这看上去非常简单,但却遇到了问题。这是我要写的方法的头
- 其实说到沉浸式状态栏这个名字我也是感到很无奈,真不知道这种叫法是谁先发起的。因为Android官方从来没有给出过沉浸式状态栏这样
- 引言在高并发的场景下,异步是一个极其重要的优化方向。前段时间,生产环境发生一次事故,笔者认为事故的场景非常具备典型性 。写这篇文章,笔者想和
- gateway、webflux、reactor-netty请求日志输出场景在使用spring cloud gateway时想要输出请求日志,
- Java反射机制在Spring IOC的应用IOC:即“控制反转”,不是什么技术,而是一种思想。使用IOC意味着将你设计好的对象交给容器控制
- using System;using System.Collections.Generic;using System.Linq;using
- 一、简介日志打印是java代码开发中不可缺少的重要一步。日志可以排查问题,可以搜集数据二、常用日志框架比较常用的日志框架就是logback,
- 简介现在的app功能越来越强大,除了基本的图文之外,还需要各种各样的其他的功能,比如视频,和直播。直播可能会比较复杂,因为涉及到了拉流和推流
- 本文实例讲述了Android开发使用Messenger及Handler进行通信的方法。分享给大家供大家参考,具体如下:1. 客户端servi
- 本文调用android的媒体播放器实现一些音乐播放操作项目布局:<LinearLayout xmlns:android="h
- 前言java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也不能做出来非常好用,
- 前言先说缓存,合理使用缓存是优化中最常见的,将从数据库中查询出来的数据放入缓存中,下次使用时不必从数据库查询,而是直接从缓存中读取,避免频繁
- Java把内存分成两种,一种叫做栈内存,一种叫做堆内存在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。
- 最近做的一个小东西遇到这样的情况,我从一个页面MainActivity修改一些内容,需要跳转到一个新的EditActivity去做修改操作,
- 由于工作中 使用 MultipartFile 与现有的一些上传文件组件冲突所以使用其他的接收上传文件的方法.首先我把 M
- 本文实例讲述了Android EditText自定义样式的方法。分享给大家供大家参考,具体如下:1.去掉边框EditText的backgro
- C# double.ToString()的用法C# 中 double 类型的数据,有时需要格式化显示为字符串(保留N位有效数字或者是保留N位
- Mybatis的日志模块的适配器模式我们在开发中日志是必不可少的一部分,而市场中有很多日志框架供我们使用,mybatis作为一个开源框架需要