Android与服务器的通信方式主要有两种:
1.Http通信
2.Socket通信
两者的最大差异在于:
1.Http连接使用的是“请求-响应方式”,即在请求时建立连接通道,当客户端向服务器发送请求后,服务端才能向客户端返回数据。
2.Socket通信则是在双方建立连接后,可以直接进行数据的传输,在连接时可实现信息的主动推送,而不需要每次由客户端向服务器发送请求。
1.何为Socket?
(1)我们常将Socket翻译为套接字,在程序内部提供与外界通信的端口,即端口通信。通过建立socket连接,可为通信双方的数据传输提供通道;
(2)socket的主要特点有数据丢失率低,使用简单易于移植;
(3)Socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用以实现进程在网络中通信。
2.Socket分类
根据不同的底层协议,Socket的实现是多样化的。这里主要介绍TCP/IP协议簇当中主要的Socket类型:流套接字(streamsocket)和数据报套接字(datagramsocket)。
(1)流套接字将TCP作为其端对端协议,提供了一个可信赖的字节流服务。
(2)数据报嵌套字使用UDP协议,提供数据打包发送数据。
笔者在做物联网智能监控系统APP过程中,需要实现手机客户端向后台服务器端发送Socket,于是写了一个客户端demo,实现三个简单的小功能“连接”、“发送”、“取消连接”:
(客户端)具体代码为:
Client:
package com.xy.socket;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SocketActivity extends AppCompatActivity {
private EditText mEditText;
private TextView mTextView;
private View view1;
private View view2;
private View view3;
private Button btn1;
private Button btn2;
private Button btn3;
private static final String TAG = "TAG";
private static final String HOST = "192.168.XXX.XXX"; //ip地址
private static final int PORT = 12345; //端口号
private PrintWriter printWriter;
private BufferedReader in;
private ExecutorService mExecutorService = null;
private String receiveMsg;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mEditText = (EditText) findViewById(R.id.mEditText);
mTextView = (TextView) findViewById(R.id.mTextView);
btn1 = (Button) findViewById(R.id.btn1);
btn2 = (Button) findViewById(R.id.btn2);
btn3 = (Button) findViewById(R.id.btn3);
mExecutorService = Executors.newCachedThreadPool();
**//为三个按钮设置监听**
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
connect(view1);
}
});
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
send(view2);
}
});
btn3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
disconnect(view3);
}
});
}
public void connect(View view) {
mExecutorService.execute(new connectService());
}
public void send(View view) {
String sendMsg = mEditText.getText().toString();
Log.e(TAG, ("connectService:" + sendMsg));
mExecutorService.execute(new sendService(sendMsg));
}
public void disconnect(View view) {
mExecutorService.execute(new sendService("0"));
}
private class sendService implements Runnable {
private String msg;
sendService(String msg) {
this.msg = msg;
}
@Override
public void run() {
printWriter.println(this.msg);
}
}
private class connectService implements Runnable {
@Override
public void run() {
try {
Socket socket = new Socket(HOST, PORT);
socket.setSoTimeout(60000);
printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream(), "UTF-8")), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
} catch (Exception e) {
Log.e(TAG, ("connectService:" + e.getMessage()));
}
}
}
}
安卓布局文件中只需要添加三个按钮控件以及一个编辑框即可,然后在上述代码中为相应控件添加监听。
布局代码为:
<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">
<EditText
android:id="@+id/mEditText"
android:layout_width="match_parent"
android:layout_height="50dp"/>
<TextView
android:id="@+id/mTextView"
android:layout_width="match_parent"
android:layout_height="50dp"/>
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="连接"/>
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="发送"/>
<Button
android:id="@+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="取消连接"/>
</LinearLayout>
服务端可以使用 TCP Test Tool 小工具进行测试(图为向后台服务器发送十六进制数据):
注:在进行测试时,通过APP发送的应为编辑框中的字符,如果想发送字节流需要通过Java字节数组进行转换。
例如:
定义private byte[ ] msgol = new byte[2];
msgol[0] = (byte) 0x06;
msgol[1] = (byte) 0x01;
图所示为通过字节数组处理后的结果: