Android 基于TCP多线程通信实现群聊天的功能
1.TCP多线程原理图

2.实现方法
(1)服务器端



(2)客户端

3.java后台代码
主界面
package com.lucky.test50socket2; import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView; public class MainActivity extends AppCompatActivity {
EditText editText;
TextView textView2;
Button button1;
ClientThread clientThread; //handler实现页面与Socket的交互,handler获取ClientThread中发送的message
@SuppressLint("HandlerLeak")
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what==0x01){
textView2.setText(msg.obj.toString());
}
}
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText=findViewById(R.id.editText);
textView2=findViewById(R.id.textView2);
button1=findViewById(R.id.button);
clientThread=new ClientThread(handler); //实例化ClientThread
new Thread(clientThread).start(); //开启客户端的线程
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message message=new Message(); //实例化一个message
message.what=0x02; //设置message的代号
message.obj=editText.getText().toString();//设置message的内容
ClientThread.handlerrev.handleMessage(message); //调用ClientThread的成员对象的方法,向服务器发送消息
}
}); }
}
服务器
package com.lucky.myserver; import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List; public class Myserver {
public static List<Socket> list; //定义一个存放socket的集合
public static void main(String[] args) throws IOException {
ServerSocket serverSocket=new ServerSocket(30004); //实例化一个服务器套接字
//while设置为死循环,等待客户端的socket请求的到来
while (true){
Socket socket=serverSocket.accept(); //获取套接字
list=new ArrayList<>();
list.add(socket);
ServerThead serverThead=new ServerThead(socket); //调用自建的ServerThead
new Thread(serverThead).start(); //启动线程
}
}
}
服务器线程
package com.lucky.myserver; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket; public class ServerThead implements Runnable {
private Socket socket;
InputStream inputStream; //输入流
OutputStream outputStream;//输出流
BufferedReader bufferedReader;
//构造方法
public ServerThead(Socket socket) throws IOException {
this.socket=socket;
inputStream=socket.getInputStream(); //获取输入流
bufferedReader=new BufferedReader(new InputStreamReader(inputStream,"utf-8")); } @Override
public void run() {
String str;
while ((str=readData())!=null){
for (Socket socket1 : Myserver.list) {
try {
outputStream=socket1.getOutputStream();
PrintStream printStream=new PrintStream(outputStream);
printStream.println(socket.getInetAddress()+":"+str);
} catch (IOException e) {
e.printStackTrace();
}
}
}
} private String readData(){
try {
return bufferedReader.readLine();
} catch (IOException e) {
Myserver.list.remove(socket); //删除套接字,避免占用内存
return null;
}
}
}
客户端
package com.lucky.test50socket2; import android.annotation.SuppressLint;
import android.os.Looper;
import android.os.Message; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.logging.Handler; public class ClientThread implements Runnable {
android.os.Handler handler1; //天坑:注意要导入android.os.Handler,handler要两种类型
InputStream inputStream;
OutputStream outputStream;
BufferedReader bufferedReader;
static android.os.Handler handlerrev; //构造方法
public ClientThread(android.os.Handler handler){
this.handler1=handler;
} @SuppressLint("HandlerLeak")
@Override
public void run() {
try {
Socket socket=new Socket("192.168.228.2",30004); //连接服务器
inputStream=socket.getInputStream();//实例化输入流
bufferedReader=new BufferedReader(new InputStreamReader(inputStream,"GBK"));
new Thread(){
@Override
public void run() {
String string;
try {
while ((string=bufferedReader.readLine())!=null){
Message message=new Message(); //实例化一个消息,通过handler发送到前台
message.what=0x01; //数据的代号
message.obj=string; //发送的数据
//信息回传给主线程(主界面)显示
handler1.sendMessage(message);
}
}catch (IOException e){
e.printStackTrace();
}
}
}.start();
/*
* 说明:如果要在非主线程中创建Handler对象,首先需要使用Looper类的prepare()方法来初始化一个Looper对象,
* 然后创建Handler对象,再使用Looper类的loop()方法启动Looper,从消息队列中获取和处理消息。
*/
Looper.prepare(); //准备handler
outputStream=socket.getOutputStream();//实例化输出流
handlerrev=new android.os.Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what==0x02){ //根据msg是否是需要发送的消息,若是,执行以下操作
String str=msg.obj.toString();
PrintStream printStream=new PrintStream(outputStream);
printStream.println(str); //将消息数据发送到服务器
}
}
};
Looper.loop(); //这句代码可以理解为循环执行run方法(最外层的run)
} catch (IOException e) {
e.printStackTrace();
}
}
}
Android 基于TCP多线程通信实现群聊天的功能的更多相关文章
- Android基于XMPP Smack openfire 开发的聊天室
Android基于XMPP Smack openfire 开发的聊天室(一)[会议服务.聊天室列表.加入] http://blog.csdn.net/lnb333666/article/details ...
- 链路的有效性检测 及 基于TCP的通信为什么需要RETRY
一.链路的有效性检测 当网络发生单通.连接被防火墙Hang住.长时间GC或者通信线程发生非预期异常时,会导致链路不可用且不易被及时发现. 特别是异常发生在凌晨业务低谷期间,当早晨业务高峰期到来时,由于 ...
- Android基于TCP的局域网聊天通信
概述 在同一局域网内,两台设备通过TCP进行通信聊天. 详细 代码下载:http://www.demodashi.com/demo/10567.html 一.准备工作 开发环境 jdk1.8 Ecli ...
- 网络编程应用:基于TCP协议【实现一个聊天程序】
要求: 基于TCP协议实现一个聊天程序,客户端发送一条数据,服务器端发送一条数据 客户端代码: package Homework1; import java.io.IOException; impor ...
- Learning-Python【28】:基于TCP协议通信的套接字
什么是 Socket Socket 是应用层与 TCP/IP 协议通信的中间软件抽象层,它是一组接口.在设计模式中,Socket 其实就是一个门面模式,它把复杂的 TCP/IP 协议族隐藏在 Sock ...
- Linux 系统编程 学习:008-基于socket的网络编程3:基于 TCP 的通信
背景 上一讲我们介绍了 基于UDP 的通信 这一讲我们来看 TCP 通信. 知识 TCP(Transmission Control Protoco 传输控制协议). TCP是一种面向广域网的通信协议, ...
- 基于WebSocket和SpringBoot的群聊天室
引入 普通请求-响应方式:例如Servlet中HttpServletRequest和HttpServletResponse相互配合先接受请求.解析数据,再发出响应,处理完成后连接便断开了,没有数据的实 ...
- 如何巧妙地在基于 TCP Socket 的应用中实现用户注册功能?
通常,在基于TCP的应用中(比如我开源的GGTalk即时通信系统),当TCP连接建立之后,第一个请求就是登录请求,只有登录成功以后,服务器才会允许客户端进行其它性质的业务请求.但是,注册用户这个功能比 ...
- Linux以下基于TCP多线程聊天室(server)
接上篇博文,本文是server端的实现,主要实现的功能,就是现实client的连接.转发client发送的消息.以及client掉线提示等功能,同一时候能够在这这上面扩展和TCP以及线程相关的功能木块 ...
随机推荐
- ParksLink修改密码
设置环境变量: ?set classpath=D:\ptc\PartsLink\srclib\jmxcore\WtLogR.jar;D:\ptc\PartsLink\srclib\log4j.jar; ...
- 【原创】4. MYSQL++ 之 SQLTypeAdapter类型、SQLQueryParms类型 与 SQLBuffer
1. mysqlpp::SQLBuffer 该类型其实就是SQLTypeAdapter传入的各种类型(int, string, double, long, String, …) 的包装,包装的结果就是 ...
- MySQL5.7插入中文乱码
参考: https://blog.csdn.net/kelay06/article/details/60870138 https://blog.csdn.net/itmr_liu/article/de ...
- 关于SO_LINGER选项的使用
结论: linux开启SO_LINGER时,如果设置l_linger为非0, 不管是阻塞socket,非阻塞socket, 在这里都会发生阻塞, 而并不是UNP所讲到的( 非阻塞socket会立即返回 ...
- opennebula 镜像池
{ "IMAGE_POOL": { "IMAGE": [ { ", ", ", "TEMPLATE": { & ...
- 面试题:hibernate 有用
1. Hibernate的工作流程? 答案: 1.通过Configuration对象读取并解析配置文件 2.读取并解析映射信息,创建SessionFactory对象 3.打开session 4.创建事 ...
- Shell +Cygwinterminal+WinMySQL 传参数授权
前言:新公司因为部分业务原因有好几百组win机器装MySQL授权登录比较麻烦,简单的写了一个shell传值自动授权的脚本,保存复用. #!/bin/bash #author liding@zlhy.c ...
- C#实现访问网络共享文件夹
C#实现访问网络共享文件夹,使用 WNetAddConnection2A 和 WNetCancelConnection2A. 在目标服务器建立共享文件夹,建立访问账号test; public enum ...
- 11.BETWEEN 操作符
BETWEEN 操作符在 WHERE 子句中使用,作用是选取介于两个值之间的数据范围. BETWEEN 操作符 操作符 BETWEEN ... AND 会选取介于两个值之间的数据范围.这些值可以是数值 ...
- OpenCV2.3.0在VS中的配置
本文为cherish总结,这里先收藏着了啦啦啦!!! vs中配置时尽量在全局配置中修改,否则每次新建项目都需要重新配置全局配置步骤如下:1.“视图”菜单 -> (其他窗口->)属性管理器 ...