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;
}
希望本文所述对大家学习有所帮助。
0
投稿
猜你喜欢
- 一、问题反馈今天公司测试向我反馈,系统用户模糊查询功能在用户名称包含特殊字符时(_、\、%)无法正常查询结果。二、问题验证1、当like中包
- 本文研究的主要是java中的null“类型”的相关实例,具体介绍如下。先给出一道简单的null相关的题目,引发我们对null的探讨,后面会根
- 一. spring配置文件:application.xml<?xml version="1.0" encoding
- 前言 在微信刚流行的时候,在摇一摇还能用来那啥的时候,我也曾深更半夜的拿着手机晃一晃。当时想的最多的就是
- 前言我们之前介绍了不少有关动画的篇章。前面介绍的动画都是只有一个动画效果,那如果我们想对某个组件实现一组动效,比如下面的效果,该怎么办?st
- 1、IO流1.流和流的分类什么是IO流?I:Input (输入)O: Ouput(输出)IO流的分类?有多种分类方式:一种方式是按照流的方向
- 本文实例讲述了java中static关键字用法,分享给大家供大家参考。具体分析如下:一、介绍:1、在类中,用static声明的成员变量为静态
- activiti使用的时候,通常需要跟业务紧密的结合在一起,有些业务非常的复杂,比如一个简单的采购流程:流程如下: 供应商上新商品
- 在windows环境下,我们通常在IDE如VS的工程中开发C++项目,对于生成和使用静态库(*.lib)与动态库(*.dll)可能都已经比较
- Java实现远程控制技术java自带的java.net.和java.awt.robot. 的混合可以用于实现通过网络对另一台计算机的远程控制
- 最近项目中使用了 MyBatis-Plus,点击看官方文档。使用一个新的框架,首先是验证框架的使用。 使用 MyBatis-Plu
- 当变换Java代码为Ceylon代码时,有时候我会遇到一些Java类构造器混淆了验证与初始化的情形。让我们使用一个简单但是人为的代码例子来说
- 要让项目实现 ssl 免密登录,首先需要开启 https 。所以先从 Spring Boot 如何开启 https 说起。创建服务端证书为了
- 笔者上次用C#写.Net代码差不多还是10多年以前,由于当时Java已经颇具王者风范,Net几乎被打得溃不成军。因此当时笔者对于这个.Net
- java文件打包jar运行有效步骤:1.cmd 到当前目录(默认包主类所在目录为例) set classpath = 默认包主类所在目录2.
- •readonly和const都是用来标识常量的[1]。•const可用于修饰class的field或者一个局部变量(local varia
- 其实如果我们不进行设置,只是修改了代码,运行程序以后,其出错界面如下图1所示:图1抛出异常如下:************** Excepti
- 对象持久化是指将内存中的对象保存到可永久保存的存储设备中(如磁盘)的一种技术。本文介绍的是除数据库之外的几种对象持久化方式。具体如下:保存成
- 本文所述为使用WinForm相对路径时需要注意的陷阱。这类错误经常会遇到!现分析如下供大家参考。在Window系统上利用相对路径进行操作时,
- springboot就是简化Spring应用中的初始化配置,快速创建项目而生的。创建springboot项目代开idea,点击File—&g