參考
1、Android Socket通信--UdpClient
2、Android UDP
3瘸恼、Android Socket通信(一)--基于UDP協(xié)議通信
截圖
1骑科、Android 客戶端
2、PC服務(wù)端:用的是SocketTool軟件模擬
流程
1哼蛆、連接DatagramSocket的服務(wù)端(ip和port):開啟異步線程和socket
2蕊梧、發(fā)送數(shù)據(jù)(DatagramPacket):異步
3、接收數(shù)據(jù)(DatagramPacket):注意連接狀態(tài)腮介,異步讀取
4肥矢、關(guān)閉連接:關(guān)閉DatagramSocket和對應線程
注意
1、異常:android.os.NetworkOnMainThreadException叠洗。 socket需要在線程中使用
2甘改、前后端統(tǒng)一傳輸或者接收協(xié)議 [requestcode size d1 d2 d3 ... ]旅东,在解析時候用得到
3、實施監(jiān)控socket的連接狀態(tài)十艾,還是用心跳包發(fā)過去抵代,然后返回數(shù)據(jù),一段時間沒有的話則代表socket連接失敗忘嫉。
4荤牍、注意receive接收數(shù)據(jù)后的有效長度(一個是預存的buffer,一個是有效結(jié)果buffer)
5庆冕、客戶端連上去后不知道為何一定要先發(fā)送一次参淫,才能接收?
6愧杯、UDP不安全涎才,有長度限制64K
代碼
1、UdpClient.java:udp-socket的客戶端力九,略微做了通用封裝耍铜,主要是連接,發(fā)送跌前,接收棕兼,然后設(shè)置監(jiān)聽
/**
* Created by wujn on 2019/2/15.
* Version : v1.0
* Function: udp client 64k限制
*/
public class UdpClient {
/**
* single instance UdpClient
* */
private static UdpClient mSocketClient = null;
private UdpClient(){}
public static UdpClient getInstance(){
if(mSocketClient == null){
synchronized (UdpClient.class) {
mSocketClient = new UdpClient();
}
}
return mSocketClient;
}
String TAG_log = "Socket";
private DatagramSocket mSocket;
private DatagramPacket sendPacket; //發(fā)送
private DatagramPacket receivePacket; //接受
// private OutputStream mOutputStream;
// private InputStream mInputStream;
private SocketThread mSocketThread;
private boolean isStop = false;//thread flag
/**
* 128 - 數(shù)據(jù)按照最長接收,一次性
* */
private class SocketThread extends Thread {
private String ip;
private int port;
public SocketThread(String ip, int port){
this.ip = ip;
this.port = port;
}
@Override
public void run() {
Log.d(TAG_log,"SocketThread start ");
super.run();
//connect ...
try {
if (mSocket != null) {
mSocket.close();
mSocket = null;
}
InetAddress ipAddress = InetAddress.getByName(ip);
mSocket = new DatagramSocket();
mSocket.connect(ipAddress, port); //連接
//設(shè)置timeout
//mSocket.setSoTimeout(3000);
Log.d(TAG_log,"udp connect = "+isConnect());
if(isConnect()){
isStop = false;
uiHandler.sendEmptyMessage(1);
}
/* 此處這樣做沒什么意義不大抵乓,真正的socket未連接還是靠心跳發(fā)送伴挚,等待服務(wù)端回應比較好,一段時間內(nèi)未回應灾炭,則socket未連接成功 */
else{
uiHandler.sendEmptyMessage(-1);
Log.e(TAG_log,"SocketThread connect fail");
return;
}
}
catch (IOException e) {
uiHandler.sendEmptyMessage(-1);
Log.e(TAG_log,"SocketThread connect io exception = "+e.getMessage());
e.printStackTrace();
return;
}
Log.d(TAG_log,"SocketThread connect over ");
//發(fā)送一次茎芋,否則不發(fā)送則收不到,不知道為啥蜈出。田弥。。
sendByteCmd(new byte[]{00},-1);//send once
//read ...
while (isConnect() && !isStop && !isInterrupted()) {
int size;
try {
byte[] preBuffer = new byte[4 * 1024];//預存buffer
receivePacket = new DatagramPacket(preBuffer, preBuffer.length);
mSocket.receive(receivePacket);
if (receivePacket.getData() == null) return;
size = receivePacket.getLength(); //此為獲取后的有效長度铡原,一次最多讀64k偷厦,預存小的話可能分包
Log.d(TAG_log, "pre data size = "+receivePacket.getData().length + ", value data size = "+size);
byte[] dataBuffer = Arrays.copyOf(preBuffer, size);
if (size > 0) {
Message msg = new Message();
msg.what = 100;
Bundle bundle = new Bundle();
bundle.putByteArray("data",dataBuffer);
bundle.putInt("size",size);
bundle.putInt("requestCode",requestCode);
msg.setData(bundle);
uiHandler.sendMessage(msg);
}
Log.i(TAG_log, "SocketThread read listening");
//Thread.sleep(100);//log eof
}
catch (IOException e) {
uiHandler.sendEmptyMessage(-1);
Log.e(TAG_log,"SocketThread read io exception = "+e.getMessage());
e.printStackTrace();
return;
}
}
}
}
//==============================socket connect============================
private String ip;
private int port;
/**
* connect socket in thread
* Exception : android.os.NetworkOnMainThreadException
* */
public void connect(String ip, int port){
this.ip = ip;
this.port = port;
mSocketThread = new SocketThread(ip, port);
mSocketThread.start();
}
/**
* socket is connect
* */
public boolean isConnect(){
boolean flag = false;
if (mSocket != null) {
flag = mSocket.isConnected();
}
return flag;
}
/**
* socket disconnect
* */
public void disconnect() {
isStop = true;
if (mSocket != null) {
mSocket.close();
mSocket = null;
}
if (mSocketThread != null) {
mSocketThread.interrupt();//not intime destory thread,so need a flag
}
}
/**
* send byte[] cmd
* Exception : android.os.NetworkOnMainThreadException
* */
public void sendByteCmd(final byte[] mBuffer,int requestCode) {
this.requestCode = requestCode;
new Thread(new Runnable() {
@Override
public void run() {
try {
InetAddress ipAddress = InetAddress.getByName(ip);
sendPacket = new DatagramPacket(mBuffer, mBuffer.length, ipAddress, port);
mSocket.send(sendPacket);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
Handler uiHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch(msg.what){
//connect error
case -1:
if (null != onDataReceiveListener) {
onDataReceiveListener.onConnectFail();
disconnect();
}
break;
//connect success
case 1:
if (null != onDataReceiveListener) {
onDataReceiveListener.onConnectSuccess();
}
break;
//receive data
case 100:
Bundle bundle = msg.getData();
byte[] buffer = bundle.getByteArray("data");
int size = bundle.getInt("size");
int mequestCode = bundle.getInt("requestCode");
if (null != onDataReceiveListener) {
onDataReceiveListener.onDataReceive(buffer, size, mequestCode);
}
break;
}
}
};
/**
* socket response data listener
* */
private OnDataReceiveListener onDataReceiveListener = null;
private int requestCode = -1;
public interface OnDataReceiveListener {
public void onConnectSuccess();
public void onConnectFail();
public void onDataReceive(byte[] buffer, int size, int requestCode);
}
public void setOnDataReceiveListener(
OnDataReceiveListener dataReceiveListener) {
onDataReceiveListener = dataReceiveListener;
}
}
MainActivity.java:使用,簡單明了
private void initListener(){
//socket connect
btn_connect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String ip = et_ip.getText().toString();
String port = et_port.getText().toString();
if(TextUtils.isEmpty(ip)){
Toast.makeText(UdpActivity.this,"IP地址為空",Toast.LENGTH_SHORT).show();
return;
}
if(TextUtils.isEmpty(port)){
Toast.makeText(UdpActivity.this,"端口號為空",Toast.LENGTH_SHORT).show();
return;
}
connect(ip, Integer.parseInt(port));
}
});
//socket disconnect
btn_disconnect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
disconnect();
}
});
//socket send
btn_send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (UdpClient.getInstance().isConnect()) {
byte[] data = et_send.getText().toString().getBytes();
send(data);
} else {
Toast.makeText(UdpActivity.this,"尚未連接燕刻,請連接Socket",Toast.LENGTH_SHORT).show();
}
}
});
//clear receive
btn_clear.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tv_receive.setText("");
}
});
}
/**
* socket data receive
* */
private void initDataReceiver(){
UdpClient.getInstance().setOnDataReceiveListener(dataReceiveListener);
}
/**
* socket connect
* */
private void connect(String ip, int port){
UdpClient.getInstance().connect(ip, port);
}
/**
* socket disconnect
* */
private void disconnect(){
UdpClient.getInstance().disconnect();
tv_state.setText("未連接");
}
/**
* socket send
* */
private void send(byte[] data){
String ip = et_ip.getText().toString();
String port = et_port.getText().toString();
UdpClient.getInstance().sendByteCmd(data,1001);
}
/**
* socket data receive
* data(byte[]) analyze
* */
private UdpClient.OnDataReceiveListener dataReceiveListener = new UdpClient.OnDataReceiveListener() {
@Override
public void onConnectSuccess() {
Log.i(TAG_log,"onDataReceive connect success");
tv_state.setText("已連接");
}
@Override
public void onConnectFail() {
Log.e(TAG_log,"onDataReceive connect fail");
tv_state.setText("未連接");
}
@Override
public void onDataReceive(byte[] buffer, int size, int requestCode) {
//獲取有效長度的數(shù)據(jù)
byte[] data = new byte[size];
System.arraycopy(buffer, 0, data, 0, size);
final String oxValue = Arrays.toString(HexUtil.Byte2Ox(data));
Log.i(TAG_log,"onDataReceive requestCode = "+requestCode + ", content = "+oxValue);
tv_receive.setText(tv_receive.getText().toString() + oxValue + "\n");
}
};
@Override
protected void onDestroy() {
UdpClient.getInstance().disconnect();
super.onDestroy();
}
2019 (* ̄(oo) ̄) 諸事順利只泼!