Android小项目————聊天室(网络编程篇)
一.前言
这是关于聊天室的第二篇博客,内容主要是聊天室的核心篇章,即网络编程,主要是客户端和电脑端的服务器的代码。
二.客户端
- 步骤
- 创建一个ClientThread类
- 数据的流动
- 当按动发送键时,将数据从EditText中提取出来,通过Handler和Message传递给发送子线程。
- 发送子线程将数据(ip+昵称+输入语句)通过Socket和输出流发送给电脑端的服务器
- 服务器将数据通过Socket发送给所有连接服务器的手机客户端
- 手机的接受子线程接受来自客户端的数据
- 接受子线程通过Handler和Message传递给主线程
- 主线程将数据拆分,并赋值给msg对象,添加到Msg集合中,并更新UI
- 代码
public class ClientThread implements Runnable {
private Socket mSocket;
private BufferedReader mBufferedReader = null;
private OutputStream mOutputStream = null;
private Handler mHandler;
public Handler revHandler;
public ClientThread(Handler handler) {
mHandler = handler;
}
@Override
public void run() {
try {
mSocket = new Socket("139.199.60.129", 9733);
Log.d("xjj","connect success");
//输入流管道到客户端
mBufferedReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
mOutputStream = mSocket.getOutputStream();//输出流,客户端到管道
//接受子线程
new Thread(){
@Override
public void run() {
super.run();
try {
String content = null;
//接收消息
while ((content = mBufferedReader.readLine()) != null) {
Log.d("xjj",content);
//将接受到的数据传递给msg对象,并标记
Message handleMsg = new Message();
handleMsg.what = 0;
handleMsg.obj = content;
mHandler.sendMessage(handleMsg);
}
}catch (IOException e){
e.printStackTrace();
}
}
}.start();//启动
//Looper类用来为一个线程开启一个消息循环。
// 默认情况下android中新诞生的线程是没有开启消息循环的。
// (主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。)
Looper.prepare();
//绑定发送线程的Handler
revHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
try {
//发送消息
String content;
content =Name.IP+"#$#" + Name.name+"#$#" + msg.obj.toString() + "\r\n";
mOutputStream.write(content.getBytes("utf-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
//Looper.loop(); 让Looper开始工作,从消息队列里取消息,处理消息。
Looper.loop();
} catch (IOException e) {
e.printStackTrace();
Log.d("xjj","");
}
}
}
三.服务器端
- 步骤
- 创建一个MyServer类(java编程,用eclipse)
- 创建一个ServerThread类
- 数据的流动
- 循环接受来自各个客户端的Socket链接
- 为每个链接创建一个子线程,并启动
- 子线程中循环接受来自该客户端的数据,并将该数据发送给所有客户端。
- 代码
MyServer类中
public class MyServer {
public static ArrayList<Socket> mSocketList = new ArrayList<>() ;
public static void main(String[] args){
try {
//创建服务器Socket
ServerSocket ss = new ServerSocket(9733);
while (true){
//监听链接
Socket s = ss.accept();
//打印信息
System.out.println("ip:"+ s.getInetAddress().getHostAddress() +"加入聊天室");
//将s加入到线程池中
mSocketList.add(s);
//启动子线程
new Thread(new ServerThread(s)).start();
}
}catch (IOException e){
e.printStackTrace();
System.out.println("服务器已崩溃");
e.printStackTrace();
}
}
}
ServerThread类中
public class ServerThread implements Runnable {
private Socket mSocket = null;
private BufferedReader mBufferedReader = null;
//构造方法
public ServerThread(Socket s)throws IOException{
mSocket = s;
//输入管道到服务器
mBufferedReader = new BufferedReader(new InputStreamReader(s.getInputStream(), "utf-8"));
}
public void run(){
try {
String content = null;
//循环接受服务器消息,如果没有接收到,说明该客户端下线,将其从线程池中删除
while ((content = mBufferedReader.readLine())!=null){
System.out.println("ip:"+ mSocket.getInetAddress().getHostAddress()+":"+content);
//循环向其他线程发送消息
for (Iterator<Socket> it = MyServer.mSocketList.iterator();it.hasNext();) {
Socket s = it.next();
try {
OutputStream os = s.getOutputStream();
os.write((content + "\n").getBytes("utf-8"));
} catch (SocketException e) {
e.printStackTrace();
it.remove();
}
}
}
}catch (IOException e){
System.out.println("接收出错");
try {
mSocket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
MyServer.mSocketList.remove(mSocket);
System.out.println("ip:"+ mSocket.getInetAddress().getHostAddress() +"退出聊天室");
}
}
}
四.其他
- 注意,在客户端中,创建Socket时我使用的ip为自己电脑的ip,如果需要正常运行,将代码中的ip换为自己电脑ip地址
- 源码百度云链接