Android⽹络聊天室实现过程中遇到的问题及解决Android⽹络聊天室实现过程中遇到的问题及解决
服务器端
思路
1. 创建服务器,绑定端⼝号
2. while(true)⽆限循环不断接收客户端的连接请求
3. 将各个客户端对应的socket添加到集合,⽅便统⼀管理
4. 为各个客户端的socket开启⼦线程,实现通信(接收,转发)
结构
在eclipse中创建两个类:Server—对应服务器;ServerThread—对应⼦线程,重写run()⽅法,实现接收和转发源码
Server.java
public class Server {
private static List<Socket> socket_list =new LinkedList<>();
public static void main(String[] args){
try(
ServerSocket server =new ServerSocket(8888);
){
//使⽤try with resources确保出现异常时服务器的关闭
try{
String hostAddress = LocalHost().getHostAddress();
System.out.println("服务器 "+ hostAddress +" 已就绪");
while(true){
Socket socket = server.accept();
/
/接收客户端的请求
socket_list.add(socket);
//添加到集合
System.out.println("ip: "+ InetAddress().getHostAddress()+" 加⼊聊天室");
new Thread(new ServerThread(socket, socket_list)).start();
//开启线程
}
}catch(UnknownHostException e){
System.out.println("不到主机名称");
e.printStackTrace();
}
}catch(IOException e){
System.out.println("服务器端⼝已被占⽤,⽆法建⽴服务器");
e.printStackTrace();
}
}
}
ServerThread.java
public class ServerThread implements Runnable {
private List<Socket> socket_list =new LinkedList<>();
private Socket mSocket = null;
public ServerThread(Socket socket, List<Socket> list){
this.mSocket = socket;
socket_list = list;
//拿到socket的集合,为转发做基础
}
@Override
public void run(){
//try with resources确保流的关闭
try(
BufferedReader br =new BufferedReader(
new InputStream()));
//读取⽂本信息,考虑可以⽤BufferedReader的readLine()⽅法读取到换⾏符
PrintStream ps =new PrintStream(
new FileOutputStream("chatting records",true));
//写出到服务器的⽂件,做记录
//println()可以直接写出换⾏符
){
String content = null;
while(true){
while((content = br.readLine())!= null){
ps.println(content);
System.out.println(content);
Iterator<Socket> it = socket_list.iterator();
/
/使⽤迭代器,获得每⼀个socket对象
while(it.hasNext()){
Socket socket = it.next();
if(socket != mSocket){
//⾃⼰不需要接收⾃⼰的消息
try{
PrintStream tps =new OutputStream());
tps.println(content);
}catch(IOException e){
//创建流对象失败,意味着此socket已关闭,客户端已下线,直接在集合中移除
}
}
}
}
}
}catch(IOException e){
System.out.println("客户端已断开连接");
ve(mSocket);
System.out.println("ip: "+ InetAddress().getHostAddress()+" 退出了聊天室");
}
}
}
重点内容
客户端之间的通信
服务端接收客户端消息,向客户端发送消息我们在Java⽹络编程已经有了相关基础.那么我们是怎么实现客户端之间的通信的呢?
我们可以在服务端创建⼀个LinkedList集合,将所有与客户端相连接的socket保存起来,在接收到⼀个socket发送过来的信息后,使⽤迭代器逐个获取所有的socket对象,⼀⼀向每⼀个socket发送信息,这样就实现了客户端之间的通信
客户端
思路
1. 登录页⾯,输⼊⽤户名,与服务器建⽴连接
2. 聊天页⾯,接收信息,发送信息,UI更新等操作
3. 考虑到多个页⾯都会⽤到socket,BufferedReader等,创建BaseActivity⽅便变量访问
BaseActivity内容
public class BaseActivity extends AppCompatActivity {
public static Socket socket;
public static BufferedReader br;
public static BufferedWriter bw;
private NotNetworkReceiver receiver;
public void notNetworkBroadcast(){
Intent intent =new Intent("ample.chatroom.NOTNETWORK");
sendBroadcast(intent);
//发送⼴播
}
@Override
protected void onResume(){
IntentFilter intentFilter =new IntentFilter();
intentFilter.addAction("ample.chatroom.NOTNETWORK");
receiver =new NotNetworkReceiver();
registerReceiver(receiver, intentFilter);
//动态注册⼴播
}
@Override
protected void onPause(){
if(receiver != null){
unregisterReceiver(receiver);
receiver = null;
}
//注销⼴播
}
private class NotNetworkReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent){
Toast.makeText(context,"⽆连接,请检查您的⽹络", Toast.LENGTH_SHORT).show();
}
}
}
重点内容
1. 权限申请
要与服务器建⽴连接,需要⾸先在Manifest获取权限,
在Manifest中添加
<uses-permission name="android.permission.INTERNET"/>
2. 与服务器建⽴连接
new Thread(new Runnable(){
@Override
public void run(){
try{
BaseActivity.socket =new Socket("192.168.1.126",8888);
//a.建⽴与服务器连接
BaseActivity.br =new BufferedReader(new InputStream()));
BaseActivity.bw =new BufferedWriter(new OutputStream()));
ChatActivity.actionStart(LoginActivity.this, userName);
finish();
}catch(IOException e){
notNetworkBroadcast();
/
/b.发送⼴播,通过⼴播接收器显⽰Toast
e.printStackTrace();
}
}
a. 在Android中,Socket socket = new Socket();需要放在⼦线程中进⾏,所以为其开启线程.
b. 与socket不同,Toast只能在主线程中显⽰,因此⽤⼴播来实现Toas显⽰
3. UI更新
与Toast相同,Ui的更新操作也只能在主线程中操作,但是我们客户端的接收和发送信息肯定是会开启⼦线程的,那么该如何进⾏编写?有两种⽅法:1.使⽤Handle完成UI更新;
2.使⽤runOnUiThread()完成更新,这⾥我使⽤的第⼆种
runOnUiThread(new Runnable(){
@Override
public void run(){
//消息更新
msgRecycleView.scrollToPosition(msgList.size()-1);
//显⽰最后⼀⾏,即最新消息
}
});
对了,在更新UI之前,记得要将消息列表进⾏更新,就像这样.
msgList.add(new Msg(content, Msg.TYPE_RECIVED));
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论