Andoird通信之简单聊天ChatApp
Android通信,大体上的逻辑是跟Java上的通信是差不多的,只是因为Android线程不能直接访问UI界面组件,所以在处理的时候有些麻烦,只要是通过Handle处理。
接下来是一个简单地手机聊天App,主要是手机终端与电脑之间的通信,比如发文字或者是发送图片。
因为涉及到发送不同类型的文件,所以需要制定以下协议:
1、消息类型,使用一个int表示,4个字节:
1、表示文字数据包;
2、表示鱼片数据包。
2、数据包的长度,使用一个int表示,4个字节
3、数据内容,使用字节数组进行传输。
关键性代码:
1、服务机与客户机之间的链接:
服务机:
ServerSocket ss = new ServerSocket(port);
Socket socket = ss.accept();
客户机:
//这个地方不能填电脑的本机地址,一定要是局域网或公网的//IP地址,wifi
socket = new Socket("10.96.23.74", 8888);
2、发送文字的代码:
//发送数据类型, 1-文本, 2-图片
dataOutputStream.writeInt(1);
//发送数据长度
dataOutputStream.writeInt(bytes. length);
//发送数据内容
dataOutputStream.write(bytes);
3、发送图片的代码:
//把一个图片文件读取到一个字节数组中
FileInputStream fis = new FileInputStream("images/jobs.png");
int len = fis.available();
byte[] bytes = new byte[len];
fis.read(bytes);
fis.close();
//发送数据类型, 1-文本, 2-图片
dataOutputStream.writeInt(2);
//数据长度
dataOutputStream.writeInt(bytes. length);
//数据内容
dataOutputStream.write(bytes);
//刷新缓存
dataOutputStream.flush();
4、Handle处理UI界面:
在客户机线程里面,handler.sendMessage(msg);
在MainActivity里面:
//创建Handler对象
Handler handler = new Handler(
//回调接口,当handler接收到消息时调用该接口的handleMessage方法
new Callback() {
//出理线程发送过来的数据
public boolean handleMessage(Message msg) {
if(msg. what == 1){
//把服务器发送过来的内容显示出来
textMsgLog.append(" 服务器: " + msg. obj .toString() +
"\n");
}
if(msg. what == 2){
//服务器发送过来的图片
Bitmap bitmap = (Bitmap)msg. obj ;
ImageSpan imageSpan = new ImageSpan(MainActivity. this,
bitmap);
//创建一个SpannableString对象,以便插//入用ImageSpan对象封装的图像
SpannableString ss = new SpannableString("img");
// 用imageSpan对象替换img
ss.setSpan(imageSpan, 0, 3,
Spannable. SPAN_EXCLUSIVE_EXCLUSIVE);
//把图片显示在界面上
textMsgLog.append(" 服务器: ");
textMsgLog.append(ss);
textMsgLog.append("\n");
}
return true;
}
});
5、在 Android Manifest.xml文件中添加网络权限:
在 uses-sdk 标签后面添加
<uses-permission android:name="android.permission.INTERNET"/>
所以,对于服务机
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public void setUp(int port){
try {
//监听port端口
ServerSocket ss = new ServerSocket(port);
//循环接收客户端的访问
while(true){
Socket socket = ss.accept();
//把客户端的连接放到线程里处理
SocketThread st = new SocketThread(socket);
st.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
//服务器监听8888端口
new Server().setUp(8888);
}
}
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
public class SocketThread extends Thread {
private Socket socket;
private DataOutputStream dataOutputStream;
public SocketThread(Socket socket) {
this. socket = socket;
}
public void run(){
try {
//得到网络连接的输入输出流对象
InputStream inputStream = socket.getInputStream();
//用数据输入流对原输入流进行封装,用于读取不同类型的数据
DataInputStream dis = new DataInputStream(inputStream);
//用数据输出流对原输出流进行封装,用于发送不同类型的数据
dataOutputStream = new DataOutputStream(socket.getOutputStream());
while(true){
//读取一个int,注意:这里是readInt方法
int msgType = dis.readInt();
//文字消息
if(msgType == 1){
//读取数据包长度
int len = dis.readInt();
//读取数据内容
byte[] bytes = new byte[len];
dis.readFully(bytes);
//转成字符串
String content = new String(bytes, "GB2312");
System. out.println(" 客户端说: "+content);
//客户端发送过来的字符串为image的话就发送一张图片过去
if(content.equals("image")){
sendImage();
} else {
//向客户端回应信息
String replyString = " 服务器收到了("+content+")";
bytes = replyString.getBytes("GB2312");
//发送数据类型, 1-文本, 2-图片
dataOutputStream.writeInt(1);
//发送数据长度
dataOutputStream.writeInt(bytes. length);
//发送数据内容
dataOutputStream.write(bytes);
//刷新缓存
dataOutputStream.flush();
}
}
//图片数据包
if(msgType == 2){
//读取数据包长度
int len = dis.readInt();
//读取数据内容
byte[] bytes = new byte[len];
dis.readFully(bytes);
//在这里可以把客户端发送的图片保存到文件,也可以做个界面显示出来,具体代码就不写了
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
//向客户端发送一张图片
public void sendImage() throws IOException{
//把一个图片文件读取到一个字节数组中
//src/wo.jpg,以文件夹ChatAppServer为起始目录
FileInputStream fis = new FileInputStream("images/wo.jpg");
int len = fis.available();
byte[] bytes = new byte[len];
fis.read(bytes);
fis.close();
//发送数据类型, 1-文本, 2-图片
dataOutputStream.writeInt(2);
//数据长度
dataOutputStream.writeInt(bytes. length);
//数据内容
dataOutputStream.write(bytes);
//刷新缓存
dataOutputStream.flush();
}
}
对于客户机
首先是Android页面:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textMsgLog"
android:text="" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<EditText
android:id="@+id/editInput"
android:layout_width="220dp"
android:layout_height="wrap_content" />
<Button
android:id="@+id/btnSend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="send"
android:text="发送" />
</LinearLayout>
</LinearLayout>
主页面:
package com.cyw.chatapp;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.Message;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ImageSpan;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private TextView textMsgLog;
private ClientThread clientThread;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout. activity_main);
//聊天记录组件
textMsgLog = (TextView)findViewById(R.id. textMsgLog);
//创建Handler对象
Handler handler = new Handler(
//回调接口,当handler接收到消息时调用该接口的handleMessage方法
new Callback() {
//出理线程发送过来的数据
public boolean handleMessage(Message msg) {
if(msg. what == 1){
//把服务器发送过来的内容显示出来
textMsgLog.append(" 服务器: " + msg. obj .toString() +
"\n");
}
if(msg. what == 2){
//服务器发送过来的图片
Bitmap bitmap = (Bitmap)msg. obj ;
ImageSpan imageSpan = new ImageSpan(MainActivity. this,
bitmap);
//创建一个SpannableString对象,以便插入用ImageSpan对象封装的图像
SpannableString ss = new SpannableString("img");
// 用imageSpan对象替换img
ss.setSpan(imageSpan, 0, 3,
Spannable. SPAN_EXCLUSIVE_EXCLUSIVE);
//把图片显示在界面上
textMsgLog.append(" 服务器: ");
textMsgLog.append(ss);
textMsgLog.append("\n");
}
return true;
}
});
//通信线程,通过handler对象与UI主现象发送数据
clientThread = new ClientThread(handler);
clientThread.start();
}
//向服务器发送文本内容
public void send(View v){
EditText editInput = (EditText)findViewById(R.id. editInput);
String msg = editInput.getText().toString();
boolean result = clientThread.sendText(msg);
if(result){
textMsgLog.append(" 我: "+msg+"\n");
editInput.setText("");
} else {
Toast. makeText(this, " 发送失败", Toast. LENGTH_LONG).show();
}
}
}
客户端处理线程:
package com.cyw.chatapp;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
public class ClientThread extends Thread {
//与UI主线程通信的中间代理
private Handler handler;
private DataOutputStream dataOutputStream;
private DataInputStream dataInputStream;
private Socket socket;
public ClientThread(Handler handler){
this. handler = handler;
}
//一定记得要在线程里访问网络
public void run(){
try {
//因为连接网络比较耗时间,会阻塞UI主线程
//所以连接到服务器的操作一定要放在线程的run里面
connect();
while(true){
//读取一个int,注意:这里是readInt方法
int msgType = dataInputStream.readInt();
//文字消息
if(msgType == 1){
//读取数据包长度
int len = dataInputStream.readInt();
//读取数据内容
byte[] bytes = new byte[len];
dataInputStream.readFully(bytes);
//转成字符串
String content = new String(bytes, "GB2312");
Message msg = new Message();
//消息类型
msg. what = 1;
//消息内容
msg. obj = content;
//发送给UI主线程
handler.sendMessage(msg);
}
//图片数据包
if(msgType == 2){
//读取数据包长度
int len = dataInputStream.readInt();
//读取数据内容
byte[] bytes = new byte[len];
dataInputStream.readFully(bytes);
//把字节数组还原成一个图片
Bitmap bitmap = BitmapFactory. decodeByteArray(bytes,
0, len);
Message msg = new Message();
//消息类型
msg. what = 2;
//消息内容
msg. obj = bitmap;
//发送给UI主线程
handler.sendMessage(msg);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
close();
}
}
//链接主机
private void connect() throws UnknownHostException, IOException {
//这个地方不能填电脑的本机地址,一定要是局域网或公网的IP地址,wifi
//IPv4 地址: 10.96.23.74 IPv6 地址: 2001:250:4400:d000::3:97b8
socket = new Socket("10.96.23.74", 8888);
//得到输入输出流对象
dataInputStream = new DataInputStream(socket.getInputStream());
dataOutputStream = new DataOutputStream(socket.getOutputStream());
}
//关闭网络连接
private void close(){
if(dataInputStream != null){
try {
dataInputStream.close();
} catch (IOException e) {
}
}
if(dataOutputStream != null){
try {
dataOutputStream.close();
} catch (IOException e) {
}
}
if(socket != null){
try {
socket.close();
} catch (IOException e) {
}
}
}
//向服务器发送数据
public boolean sendText(String content){
try {
//把字符串转成字节数组
byte[] bytes = content.getBytes("GB2312");
//消息类型
dataOutputStream.writeInt(1);
//数据长度
dataOutputStream.writeInt(bytes. length);
//发送数据
dataOutputStream.write(bytes);
dataOutputStream.flush();
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}
<!--EndFragment-->
- ChatAppServer.zip (53.6 KB)
- 下载次数: 1
Andoird通信之简单聊天ChatApp的更多相关文章
- JAVA基础知识之网络编程——-基于TCP通信的简单聊天室
下面将基于TCP协议用JAVA写一个非常简单的聊天室程序, 聊天室具有以下功能, 在服务器端,可以接受客户端注册(用户名),可以显示注册成功的账户 在客户端,可以注册一个账号,并用这个账号发送信息 发 ...
- Android笔记——Socket通信实现简单聊天室
两部分,客户端和服务端 ---------------------------------------------------------------- 客户端 1.为防止ANR异常,互联网连接可用 ...
- 基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。
基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍.最后我们将会实现一个基于S ...
- 利用socket.io+nodejs打造简单聊天室
代码地址如下:http://www.demodashi.com/demo/11579.html 界面展示: 首先展示demo的结果界面,只是简单消息的发送和接收,包括发送文字和发送图片. ws说明: ...
- AngularJS作出简单聊天机器人
简单聊天机器人 很初级的对话框形式.以前做对话框使用js,今天尝试使用AngularJS做出来 这里直接使用自己写的JSON数据. <!DOCTYPE html> <html lan ...
- iOS中XMPP简单聊天实现 好友和聊天
版权声明本文由陈怀哲首发自简书:http://www.jianshu.com/users/9f2e536b78fd/latest_articles;微信公众号:陈怀哲(chenhuaizhe2016) ...
- Python Socket 简单聊天室2
上篇文章写了一个简单的单线程的一问一答的简单聊天室.这次我们使用SocketServer模块搭建一个多线程异步的聊天室. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ...
- Asp.Net SignalR - 简单聊天室实现
简单聊天室 使用持久链接类我们就可以做一些即时通讯的应用了,我使用Group做了一个简单的聊天室,先上图技术细节下面再讲 可以加入聊天室.创建聊天室.发送消息,下面就说说我是如何通过Group做出来的 ...
- SpringBoot 搭建简单聊天室
SpringBoot 搭建简单聊天室(queue 点对点) 1.引用 SpringBoot 搭建 WebSocket 链接 https://www.cnblogs.com/yi1036943655/p ...
随机推荐
- Nginx配置基于多域名、端口、IP的虚拟主机
原文:https://www.cnblogs.com/ssgeek/p/9220922.html ------------------------------- Nginx配置基于多域名.端口.IP的 ...
- PHP的异常以及异常存在的意义
php的try catch与其它语言的try catch相比有许多不同,而且用起来相对比较不爽. php中,如果你制作的站点相对较大,同时模块化,并且在错误处理机制上有一套自己的处理机制,可以尝试使用 ...
- C#.NET常见问题(FAQ)-索引器indexer有什么用
索引器就是名值对,你声明一个名值对的类,就可以给数组的指定元素赋值,也可以很方面的访问到指定元素值对应的下标(个人认为完全可以自己写一个类似的list来实现,没有必要多此一举学一个额外的方法) 复 ...
- iOS 开发者证书总结 in-house
iOS 证书分两种类型. 第一种为$99美元的,这种账号有个人和公司的区别,公司账号能创建多个子账号,但个人的不能.这种账号可以用来上传app store 第二种为¥299美元的,这种账号只能用于企业 ...
- Spring开发 - 通过实现ApplicationContextAware在Servlet中调用注解的Service
用过Spring MVC的人都知道,我们如何在Controller中注入Service,可以使用@Resource注解的方法. 有时候,实际在项目的过程中,我们需要在某个Servlet中使用Servi ...
- Plupload上传插件中文帮助文档
Plupload上传插件中文帮助文档 配置参数 实例化一个plupload对象时,也就是 new plupload.Uploader(),需要传入一个对象作为配置参数.后面内容中出现的plupload ...
- TCP三次握手详解
当两台主机采用 TCP 协议进行通信时,在交换数据前将建立连接.通信完成后,将关闭会话并终止连接.连接和会话机制保障了TCP 的可靠性功能. 请参见图中建立并终止 TCP 连接的步骤. 主机将跟踪会话 ...
- hadoop mahout 算法和API说明
org.apache.mahout.cf.taste.hadoop.item.RecommenderJob.main(args) --input 偏好数据路径,文本文件.格式 userid\t ite ...
- LIST OF NOSQL DATABASES [currently 150]
http://nosql-database.org Core NoSQL Systems: [Mostly originated out of a Web 2.0 need] Wide Column ...
- ROS知识(15)----Actionlib的使用(一)
Actionlib是ROS非常重要的库,像执行各种运动的动作,例如控制手臂去抓取一个杯子,这个过程可能复杂而漫长,执行过程中还可能强制中断或反馈信息,这时Actionlib就能大展伸手了. 1.原理 ...