1、问题
局域网内两个手机互相发送和接受图片
2、方法
通过socket连接,注意,socket是TCP协议的,是面向字节流的,所以发送数据要报头和数据的大小,这样接受方就可以很准确的获得图片
3、代码
1、客户端
①截取Activity的屏幕,与01的方法不一样,这个只是为了熟悉socket,所以只用简单的
②连接服务器
③发送数据
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
screenshot();
}
private void screenshot() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
// 获取屏幕
View dView = getWindow().getDecorView();
// 把屏幕存储在Bitmap
dView.destroyDrawingCache();
dView.setDrawingCacheEnabled(true);
dView.buildDrawingCache();
Bitmap bmp = dView.getDrawingCache();
if (bmp != null) {
try {
// 获取内置SD卡路径
String sdCardPath = Environment.getExternalStorageDirectory().getPath();
// 图片文件路径
String filePath = sdCardPath + File.separator + "screenshot.png";
Log.d("path", filePath);
File file = new File(filePath);
FileOutputStream os = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.PNG, 30, os);
Upload upload = new Upload();
upload.uploadFile(file);
os.flush();
os.close();
Toast.makeText(MainActivity.this, "wan", Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(MainActivity.this, "shi1", Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(MainActivity.this, "shi2", Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
}
}
}
}).start();
}
}
Upload类
@SuppressLint("NewApi")
public class Upload {
// 这里的地址为HOME
private static final String HOME = "192.168.0.102";
private static final String BUFF = "--";
Socket socket = null;
DataOutputStream output = null;
DataInputStream input = null;
public void uploadFile( final File file) {
// 如果本系统为4.0以上(Build.VERSION_CODES.ICE_CREAM_SANDWICH为android4.0)
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// 详见StrictMode文档
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads().detectDiskWrites().detectNetwork()
.penaltyLog().build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects().detectLeakedClosableObjects()
.penaltyLog().penaltyDeath().build());
}
new Thread(new Runnable() {
@Override
public void run() {
try {
// 连接服务器
socket = new Socket(HOME, 8888);
// 得到输出流
output = new DataOutputStream(socket.getOutputStream());
// 得到如入流
input = new DataInputStream(socket.getInputStream());
/* 取得文件的FileInputStream */
FileInputStream fStream = new FileInputStream(file);
String[] fileEnd = file.getName().split("\\.");
output.writeUTF(BUFF + fileEnd[fileEnd.length - 1].toString());
Log.d("path","buffer------------------" + BUFF
+ fileEnd[fileEnd.length - 1].toString());
//设置每次写入102400bytes
int bufferSize = 302400;
byte[] buffer = new byte[bufferSize];
int length = 0;
// 从文件读取数据至缓冲区(值为-1说明已经读完)
while ((length = fStream.read(buffer)) != -1) {
/* 将资料写入DataOutputStream中 */
output.write(buffer, 0, length);
}
// 一定要加上这句,否则收不到来自服务器端的消息返回
socket.shutdownOutput();
/* close streams */
fStream.close();
output.flush();
/* 取得input内容 */
String msg = input.readUTF();
Log.d("path","上传成功 文件位置为:" + msg);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
}
2、服务器
①监听端口
②连接服务器
③接受数据
④显示在ImageView
public class MainActivity extends AppCompatActivity {
// ServerSocket的引用
ServerSocket ss = null;
// socket的引用
Socket socket = null;
DataInputStream input = null;
DataOutputStream output = null;
// 报头,验证用
public final static byte[] PICTURE_PACKAGE_HEAD = {(byte) 0xFF, (byte) 0xCF,
(byte) 0xFA, (byte) 0xBF, (byte) 0xF6, (byte) 0xAF, (byte) 0xFE,
(byte) 0xFF};
// socket端口
private final static int PORT = 8888;
static ImageView imageView;
//由于更新UI一定要这样弄子线程,由于UI消耗太大
private static Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Bitmap bitmap = BitmapFactory.decodeByteArray((byte[]) msg.obj, 0,msg.what );
imageView.setImageBitmap(bitmap);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView=findViewById(R.id.image);
new Thread(new Runnable() {
@Override
public void run() {
// 服务器监听功能是一直存在的
try {
// 监听到8888端口
ss = new ServerSocket(PORT);
Log.d("path","已监听到" + PORT + "端口");
Log.d("path",new Date().toString() + " \n 服务器已经启动...");
// 判断是否连接了客户端
while(socket == null || socket.isClosed())
socket = ss.accept();
Log.d("path",new Date().toString() + " \n 已经连接客户端...");
// 得到输入流
input = new DataInputStream(socket.getInputStream());
// 得到输出流
output = new DataOutputStream(socket.getOutputStream());
// 更新UI
SocketUpLoad(input);
} catch (IOException e) {
Log.d("path","连接客户端失败") ;
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
/**
* 上传
*
* @param input
*/
private void SocketUpLoad(final DataInputStream input) {
new Thread(new Runnable() {
@Override
public void run() {
while(true)
try {
Thread.sleep(3000);
// DataInputStream inputStream = input;
//标志头状态
boolean isHead = true;
//循环读取PICTURE_PACKAGE_HEAD.length个字节,并判断是否和我们定义的头相同
for (int i = 0; i < PICTURE_PACKAGE_HEAD.length; ++i) {
// Log.d("path","成功1") ;
byte head = (byte) input.read();
// Log.d("path","成功2") ;
//如果不相同,那么结束循环,并丢弃这个字节
if (head != PICTURE_PACKAGE_HEAD[i]) {
isHead = false;
Log.d("path","失败,报头不一样") ;
break;
}
}
// Log.d("path","获得报头") ;
if(isHead){
long picLeng = input.readLong();
//new 一个字节数据输出流
ByteArrayOutputStream fos = new ByteArrayOutputStream();
//每一次读CACHE_SIZE个字节,
byte[] buffer = new byte[102400];
int len = -1;
//循环读取
while (picLeng > 0 && (len = input.read(buffer, 0, picLeng < buffer.length ? (int) picLeng : buffer.length)) != -1) {
fos.write(buffer, 0, len);
fos.flush();
//每读取后,picLeng的值要减去len个,直到picLeng = 0
picLeng -= len;
}
fos.flush();
buffer = null;
// 如果发现picLeng 不为0,说明图片接收不完整,那么就放弃这段数据
if (picLeng > 0) {
continue;
}
//如果以上操作都成功,那么就取出图片数据
byte[] pictures = fos.toByteArray();
//然后使用相应的工具类就可以把pictures转化为图片了
fos.close();
fos = null;
Message message = new Message();
message.obj = pictures;
message.what = pictures.length;
handler.sendMessage(message);
Log.d("path","获得图片数据") ;
}
}catch (Exception e){
Log.d("path","run中失误") ;
}
}
}).start();
}
四、
先去看看socket工作原理
五、
完成版:源码
参考资料
android选择图片并使用socket上传图片
Java Socket连续传输多张图片(不断开链接)