Android-socket的基本使用,发送文字和图片以及心跳

要求发送的消息的格式是,8个字节的消息长度+消息体

Android-socket的基本使用,发送文字和图片以及心跳

文章插图
因为需要8个字节,所以消息长度决定用long
如果需要4个字节 , 可以用int 。
手机客户端接收服务器的文字消息 服务端
服务端定义好端口号,开启以一个,写入文字消息:
public class Service {private static Socket socket;//定义端口号private static final int POST = 30000;public static void main(String[] args) {try {//发送的内容sendMsg("来自服务器的问候");} catch (IOException e) {e.printStackTrace();}}public static void sendMsg(String msg) throws IOException {System.out.println("开始连接");//创建socket服务端口是30000,并等待连接ServerSocket serverSocket = new ServerSocket(POST);Socket socket = serverSocket.accept();//获取输出流DataOutputStream out = new DataOutputStream(socket.getOutputStream());sendTextMsg(out, msg);out.close();socket.close();serverSocket.close();System.out.println("通讯结束");}public static void sendTextMsg(DataOutputStream out, String msg) throws IOException {//先写长度,就是消息体的字节数,long刚好8个字节out.writeLong(msg.getBytes().length);//写入消息out.write(msg.getBytes());}}
客户端,接收消息
客户端首先要跟服务器进行连接,然后才能进行通讯 。
连接需要网络权限:

因为属于网络通讯 , 所以连接也不能放在主线程中,否则会报错
Android-socket的基本使用,发送文字和图片以及心跳

文章插图
运行测试
先运行服务端,会发现程序没有一次执行完,在阻塞着等待连接
Android-socket的基本使用,发送文字和图片以及心跳

文章插图
这时点击app中的接收按钮,日志中会打印接收到的信息
长度为24,消息内容为“来自服务器的问候” 。
因为在utf-8中一个汉字是3个字节,所以8个汉字的消息长度是24字节 。
这是看服务器端的打?。?
Android-socket的基本使用,发送文字和图片以及心跳

文章插图
发现服务端也正常执行完毕了 。
手机客户端向服务端发送文字消息 服务端接收消息
public class Service {private static Socket socket;//定义端口号private static final int POST = 30000;public static void main(String[] args) {try {//接收消息getMsg();} catch (IOException e) {e.printStackTrace();}}public static void getMsg() throws IOException {System.out.println("开始连接");ServerSocket serverSocket = new ServerSocket(POST);Socket socket = serverSocket.accept();//获取输入流,通过这个流来读取消息DataInputStream input = new DataInputStream(socket.getInputStream());//接收文字消息getTextMsg(input);input.close();socket.close();serverSocket.close();System.out.println("通讯结束");}public static String getTextMsg(DataInputStream input) throws IOException {//一样先读长度,再根据长度读消息long len = input.readLong();System.out.println("len = " + len);byte[] bytes = new byte[(int) len];input.read(bytes);String msg = new String(bytes);System.out.println("msd = " + msg);return msg;}}
客户端发送消息

public void send(View view) {new Thread(new Runnable() {@Overridepublic void run() {Socket socket;try {//建立连接socket = new Socket(host, post);//获取输出流 , 通过这个流发送消息DataOutputStream out = new DataOutputStream(socket.getOutputStream());//发送文字消息sendTextMsg(out,"来自手机客户端的消息");out.close();socket.close();} catch (IOException e) {e.printStackTrace();}}}).start();}public void sendTextMsg(DataOutputStream out, String msg) throws IOException {byte[] bytes = msg.getBytes();long len = bytes.length;//先发送长度,在发送内容out.writeLong(len);out.write(bytes);}
运行测试
先运行服务端,也会停留着这个界面等待连接:
Android-socket的基本使用,发送文字和图片以及心跳

文章插图
然后点击客户端的发送按钮,这是服务端会变成下面这样,完成这次消息的通讯
【Android-socket的基本使用,发送文字和图片以及心跳】
Android-socket的基本使用,发送文字和图片以及心跳

文章插图
手机客户端想服务端发送图片 服务端接收图片,并保存到本地
在上面的()方法中,将(input);改为(input);
下面是(input);方法:
public static void getImgMsg(DataInputStream input) throws IOException {//同样是先读长度long len = input.readLong();System.out.println("len = " + len);byte[] bytes = new byte[(int) len];//然后在读这个长度的字节到字节数组input.readFully(bytes);//将独到的内容保存为文件到本地File file = new File("/Users/xxx/" + len + ".png");FileOutputStream fileOutputStream = new FileOutputStream(file);fileOutputStream.write(bytes);System.out.println("ok");}
客户端发送图片

运行测试
还是先开启服务端 , 服务器变成:
Android-socket的基本使用,发送文字和图片以及心跳

文章插图
然后点击app的发送图片按钮,app中打印日志:
说明发送的图片的长度是11418个字节,大致换算大小是11k 。
Android-socket的基本使用,发送文字和图片以及心跳

文章插图
然后看服务端的日志:
Android-socket的基本使用,发送文字和图片以及心跳

文章插图
接收到的长度也是11418,并且保存到了文件 , 
Android-socket的基本使用,发送文字和图片以及心跳

文章插图
关于心跳包
上面的例子中,每发送一次之后就把链接关闭了:
out.close();socket.close();serverSocket.close();
心跳其实就是定期向服务端发送一个小数据 , 比如0.
让服务器知道这个链接还有用,不用关闭 。
简单实现起来就是客户端通过一个无限循环,不停地向服务端发送消息,服务端通过一个无限循环不停地接收消息,都不关闭这个链接就行了 。
服务端
public static void main(String[] args) {try {System.out.println("开始接收信息");ServerSocket serverSocket = new ServerSocket(POST);socket = serverSocket.accept();DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());new Thread(new Runnable() {@Overridepublic void run() {while (true) {try {long len = 0;len = dataInputStream.readLong();System.out.println("len = " + len);byte[] bytes = new byte[(int) len];dataInputStream.readFully(bytes);String s = new String(bytes);System.out.println("data = "http://www.kingceram.com/post/+ s);} catch (IOException e) {e.printStackTrace();isConnect = false;}}}}).start();} catch (IOException e) {e.printStackTrace();}}
客户端,一秒发送一次消息
try {//建立一次链接socket = new Socket(host,post);outputStream = new DataOutputStream(socket.getOutputStream());inputStream = new DataInputStream(socket.getInputStream());} catch (IOException e) {e.printStackTrace();}Log.i(TAG, "run: 开始循环发送发送心跳");//一秒发送一个0 , while (true){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}Log.i(TAG, "run: 发送心跳0");try {outputStream.writeLong("0".getBytes().length);outputStream.write("0".getBytes());} catch (IOException e) {e.printStackTrace();isConnect = false;}}
运行测试
先运行服务端:
Android-socket的基本使用,发送文字和图片以及心跳

文章插图
然后点击发送心跳的按钮,app的日志中打?。?
Android-socket的基本使用,发送文字和图片以及心跳

文章插图
在服务端的日志中可以看到:
Android-socket的基本使用,发送文字和图片以及心跳

文章插图
一秒一次
Android-socket的基本使用,发送文字和图片以及心跳

文章插图