Socket通信 客户端(Android)
Posted 编程很难
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Socket通信 客户端(Android)相关的知识,希望对你有一定的参考价值。
Socket通信长连接
socket网络编程
什么是socket?
Socket的英文原义是“孔”或“插座”。在网络编程中,网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。
Socket套接字是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
Socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。
Socket的原理
Socket实质上提供了进程通信的端点。进程通信之前,双方首先必须各自创建一个端点,否则是没有办法建立联系并相互通信的
套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。
1、服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。
2、客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
3、连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
实例
申请权限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
SocketClient
import android.os.Handler;
import android.os.Message;
import android.util.Log;
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.InetSocketAddress;
import java.net.Socket;
public class SocketClient implements Runnable {
protected static SocketClient mInstance;
protected Handler mHandler;
protected InetSocketAddress mAddress;
protected String TAG = "SocketClient";
private final int TIME_OUT = 5 * 1000;
//巡检周期
private final int CHECK_PERIOD = 2 * 1000;
//连接尝试间隔时间
private final int CONNECT_PERIOD = 3 * 1000;
public final int HEARTBEART_PERIOD = 10 * 1000;
//若连接失败或响应失败,则尝试次数为9,若仍无效,则不再尝试
private final int CONNECT_TRY_TIMES = 10;
//连接尝试次数
private int mConnectCount;
Socket mClientSocket;
String mHost;
int mPort;
//设置是否去读取数据
boolean isStartRecieveMsg = false;
//开启心跳检测
boolean isKeepHeartBeat = true;
private SocketClient(Handler handler) {
mHandler = handler;
}
public static SocketClient getInstance(Handler handler) {
if (mInstance == null) {
mInstance = new SocketClient(handler);
}
return mInstance;
}
public void init(String host, int port) {
mHost = host;
mPort = port;
new Thread(this).start();
}
public boolean isConnected(){
if (mClientSocket!=null && mClientSocket.isConnected()){
return true;
}
return false;
}
@Override
public void run() {
mAddress = new InetSocketAddress(mHost, mPort);
if (mClientSocket == null) {
mClientSocket = new Socket();
}
//尝试连接,若未连接,则设置尝试次数
retryConnect();
if (mClientSocket.isConnected()) {
isStartRecieveMsg = true;
isKeepHeartBeat = true;
sendMsg("android connect success");
keepHeartBeat();//心跳保持
recvMsg();//获取数据
}
}
public void retryConnect() {
if (mClientSocket == null){
Log.e(TAG,"Reconnect mClientSocket null");
init("ip",port);
return;
}
while ((!mClientSocket.isConnected() ||mClientSocket.isClosed()) && mConnectCount < CONNECT_TRY_TIMES) {
Log.e(TAG,"Reconnect after disconnection");
connect();
if (!mClientSocket.isConnected()) {
mConnectCount++;
sleep(CONNECT_PERIOD);
} else {
mConnectCount = 0;//连接上,则恢复置0
}
}
}
// private void isConnectIng() {
// while (true){
//
// }
// }
private void connect() {
try {
mClientSocket.connect(mAddress);
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "mClientSocket.connect fail " + e.getMessage());
}
}
/**
* 心跳维护
*/
private void keepHeartBeat() {
//设置心跳频率,启动心跳
// sendMsg("keepHeartBeat");
// while(isKeepHeartBeat){
if (isKeepHeartBeat) {
Message message = new Message();
message.what = 1002;
mHandler.sendMessageDelayed(message, HEARTBEART_PERIOD);
// sleep(HEARTBEART_PERIOD);
}
// }
}
BufferedWriter mWriter;
BufferedReader mReader;
/**
* 不断的检测是否有服务器推送的数据过来
*/
public void recvMsg() {
Log.e(TAG,"recvMsg");
while (mClientSocket != null && mClientSocket.isConnected() && !mClientSocket.isClosed()) {
Log.e(TAG,"recvMsg1");
try {
mReader = new BufferedReader(new InputStreamReader(mClientSocket.getInputStream(), "utf-8"));
while (isStartRecieveMsg) {
if (mReader.ready()) {
/*读取一行字符串,读取的内容来自于客户机
reader.readLine()方法是一个阻塞方法,
从调用这个方法开始,该线程会一直处于阻塞状态,
直到接收到新的消息,代码才会往下走*/
String data = mReader.readLine();
Log.e(TAG,"服务端返回数据="+data);
//handler发送消息,在handleMessage()方法中接收
// handlerMsg(data);
}
// Log.e(TAG,"recvMsg not ready");
Thread.sleep(1000);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
Log.e(TAG,"recvMsg ex");
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG,"recvMsg e");
} catch (Exception ex) {
ex.printStackTrace();
Log.e(TAG,"recvMsg ex2");
}
sleep(200);
}
if (!mClientSocket.isConnected()) {
connect();
recvMsg();
}
sleep(CHECK_PERIOD);
}
private void sleep(long sleepTime) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 销毁socket
*/
public void onDestory() {
if (mClientSocket != null) {
try {
mClientSocket.close();
Log.e(TAG,"close success");
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG,"close error");
}
mClientSocket = null;
}
}
public void sendMsg(String message) {
PrintWriter writer;
try {
writer = new PrintWriter(new OutputStreamWriter(
mClientSocket.getOutputStream()), true);
writer.println(message);
// writer.flush();
Log.e(TAG,"sendMsg success "+message);
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG,"sendMsg error "+message);
}catch (Exception e){
Log.e(TAG,"sendMsg error "+message + " error: " + e.getMessage());
}
}
/*
* Ready for use.
*/
public void close() {
try {
if (mClientSocket != null && !mClientSocket.isClosed())
mClientSocket.close();
Log.e(TAG,"close success");
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG,"close error");
}catch (Exception e){
Log.e(TAG,"close error");
}
}
/**
* 处理服务器返回过来的消息
* @param data
*/
private void handlerMsg(String data){
//对数据进行protobuf解析
//消息类型:1=登录成功、2=心跳检测、3=推送消息
int msgType=1;
switch(msgType){
case 1:
sendMsg("success");
break;
case 2:
sendMsg("success");
break;
case 3: //需要通知service
sendMsg("success");
mHandler.obtainMessage(1001, data).sendToTarget();
break;
}
}
Activity层调用
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Toast;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Main2Activity extends AppCompatActivity {
private SocketClient client;
private NetWorkStateReceiver netWorkStateReceiver;
Thread thread = new Thread(){
@Override
public void run() {
super.run();
client.sendMsg("我是Android 发送 心跳包");
}
};
private ThreadPoolExecutor poolExecutor;
//在onResume()方法注册
@Override
protected void onResume() {
if (netWorkStateReceiver == null) {
netWorkStateReceiver = new NetWorkStateReceiver();
}
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(netWorkStateReceiver, filter);
Toast.makeText(this, "register NetWorkStateReceiver", Toast.LENGTH_SHORT).show();
super.onResume();
netWorkStateReceiver.setNetCallback(new NetWorkStateReceiver.NetWorkChangeListener() {
@Override
public void connect() {
client.retryConnect();
}
@Override
public void disconnect() {
// client.close();
client.onDestory();
}
});
}
@Override
protected void onPause() {
unregisterReceiver(netWorkStateReceiver);
Toast.makeText(this, "unregister NetWorkStateReceiver", Toast.LENGTH_SHORT).show();
client.close();
client.onDestory();
super.onPause();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
poolExecutor = new ThreadPoolExecutor(5, 10, 15, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
client = SocketClient.getInstance(new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 1002:
poolExecutor.execute(thread);
// thread.start();
Message message = new Message();
message.what = 1002;
client.mHandler.sendMessageDelayed(message, client.HEARTBEART_PERIOD);
break;
}
}
});
}
public void connectSocket 通信原理(Android客户端和服务器以TCP&&UDP方式互通)