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

来源:互联网 发布:ppt转pdf软件在线 编辑:程序博客网 时间:2024/05/16 15:51

项目需求收集通过Socket向服务器发送图片,之前没搞过,网上搜搜写了下面的例子,勉强解决了需求。

为了测试切换着方便,所以方法写的有点碎了。。。
原文地址 http://blog.csdn.net/qq_25806863/article/details/75533109

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

因为需要8个字节,所以消息长度决定用long

如果需要4个字节,可以用int

手机客户端接收服务器的文字消息

服务端

服务端定义好端口号,开启以一个ServerSocket,写入文字消息:

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());    }}

客户端,接收消息

客户端首先要跟服务器进行连接,然后才能进行通讯。

Socket连接需要网络权限:

<uses-permission android:name="android.permission.INTERNET"/>

因为属于网络通讯,所以socket连接也不能放在主线程中,否则会报错

  • 添加按钮

    在布局中加一个按钮,点击方法是receive

    <Button  android:text="接收"  android:layout_marginTop="50dp"  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:onClick="receive"/>
  • 定义方法

    在Activity中定义方法

    因为不能再主线程中访问,所以需要子线程。这里直接new了、、

    public void receive(View view){  new Thread(new Runnable() {      @Override      public void run() {          Socket socket;          try {            //这里进行连接服务器,            //host是服务器ip地址,如“192.168.2.12”            //post是端口,上面的服务端提供的端口号是30000              socket = new Socket(host, post);            //获取输入流              DataInputStream input = new DataInputStream(socket.getInputStream());            //读取长度,也即是消息头,              long len = input.readLong();            //创建这个长度的字节数组              byte[] bytes = new byte[(int)len];            //再读取这个长度的字节数,也就是真正的消息体              input.read(bytes);            //将字节数组转为String              String s = new String(bytes);              Log.i("accept", "len: "+len);              Log.i("accept", "msg: "+s);          } catch (IOException e) {              e.printStackTrace();          }      }  }).start();}

运行测试

先运行服务端,会发现程序没有一次执行完,在阻塞着等待连接

这时点击app中的接收按钮,日志中会打印接收到的信息

长度为24,消息内容为“来自服务器的问候”。

因为在utf-8中一个汉字是3个字节,所以8个汉字的消息长度是24字节。

这是看服务器端的打印:

发现服务端也正常执行完毕了。

手机客户端向服务端发送文字消息

服务端接收消息

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;    }}

客户端发送消息

  • 增加一个发送的按钮:
<Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="发送!"        android:onClick="send"/>
  • 定义方法
public void send(View view) {        new Thread(new Runnable() {            @Override            public 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);    }

运行测试

先运行服务端,也会停留着这个界面等待连接:

然后点击客户端的发送按钮,这是服务端会变成下面这样,完成这次消息的通讯

手机客户端想服务端发送图片

服务端接收图片,并保存到本地

在上面的getMsg()方法中,将getTextMsg(input);改为getImgMsg(input);

下面是getImgMsg(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");}

客户端发送图片

  • 增加一个按钮:
<Button    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_marginTop="200dp"    android:onClick="sendImg"    android:text="发送图片" />
  • 定义方法

    public void sendImgMsg(DataOutputStream out ) throws IOException {//发送的图片为图标,就是安卓机器人,将bitmap转为字节数组  Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_round);  ByteArrayOutputStream bout = new ByteArrayOutputStream();  bitmap.compress(Bitmap.CompressFormat.PNG,100,bout);//写入字节的长度,再写入图片的字节  long len = bout.size();//这里打印一下发送的长度  Log.i("sendImgMsg", "len: "+len);  out.writeLong(len);  out.write(bout.toByteArray());}

运行测试

还是先开启服务端,服务器变成:

然后点击app的发送图片按钮,app中打印日志:

说明发送的图片的长度是11418个字节,大致换算大小是11k。

然后看服务端的日志:

接收到的长度也是11418,并且保存到了文件,

关于心跳包

上面的例子中,每发送一次之后就把链接关闭了:

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() {                @Override                public 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 = " + 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;    }}

运行测试

先运行服务端:

然后点击发送心跳的按钮,app的日志中打印:

在服务端的日志中可以看到:

一秒一次

阅读全文
1 0
原创粉丝点击