Android Socket 专题:
UDP Client客户端 http://blog.csdn.net/shankezh/article/details/50731287
UDP Server服务器 http://blog.csdn.net/shankezh/article/details/51452811
TCP Client客户端 http://blog.csdn.net/shankezh/article/details/70763579
TCP Server服务器 http://blog.csdn.net/shankezh/article/details/51555455
关于UDP通信其实可以不用多做累述,多数像我一样的朋友在此基础上也只是为了应用,需要了解下该了解的就可以了,具体的想要对这个协议研究深入的,可以自己努力!我这儿只做Android客户端的应用实现,注意是客户端,不是服务器,那么服务器怎么实现呢? 点击上方,已经补充!!!
规划自己的界面的(非常简单):
XML实现效果图如下:
附上对应XML代码:
首先在写代码前要说明下关键性的几个类,我们完成udp客户端其实主要就是通过这几个类实现的:
1、DatagramSocket
2、DatagramPacket
3、InetAddress
关于这几个类到底是什么意思,包含了什么信息,大家可以自己去百度谷歌,或者直接打开JAVA API文档查看便知,这里不做赘述,看具体实现。
关于UDP客户端收发这里,实现思路是:
启动UDP线程:
1、创建DatagramSocket通信数据报
2、建立接收事件专用DatagramPacket数据包
3、创建超时(这个和后面关闭通信有关)
4、建立监听接收消息循环机制(接收消息处理在此处,接收到的消息通过BroadcastReceiver发送给主界面)
5、结束循环,关闭数据报。
以上为收取信息思路,发送信息则为UDP线程中的一个方法,直接被调用,共享了接收块的DatagramSocket数据报:
UDP Thread Run--->[Function方法]send(String SendMsg)
下面看具体代码实现:
package jiugaosh.com.udpdemo;
import android.content.Intent;
import android.util.Log;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
/**
* Created by lenovo on 2016/2/23.
*/
public class UDPClient implements Runnable{
final static int udpPort = 9999;
final static String hostIp = "192.168.1.4";
private static DatagramSocket socket = null;
private static DatagramPacket packetSend,packetRcv;
private boolean udpLife = true; //udp生命线程
private byte[] msgRcv = new byte[1024]; //接收消息
public UDPClient(){
super();
}
//返回udp生命线程因子是否存活
public boolean isUdpLife(){
if (udpLife){
return true;
}
return false;
}
//更改UDP生命线程因子
public void setUdpLife(boolean b){
udpLife = b;
}
//发送消息
public String send(String msgSend){
InetAddress hostAddress = null;
try {
hostAddress = InetAddress.getByName(hostIp);
} catch (UnknownHostException e) {
Log.i("udpClient","未找到服务器");
e.printStackTrace();
}
/* try {
socket = new DatagramSocket();
} catch (SocketException e) {
Log.i("udpClient","建立发送数据报失败");
e.printStackTrace();
}*/
packetSend = new DatagramPacket(msgSend.getBytes() , msgSend.getBytes().length,hostAddress,udpPort);
try {
socket.send(packetSend);
} catch (IOException e) {
e.printStackTrace();
Log.i("udpClient","发送失败");
}
// socket.close();
return msgSend;
}
@Override
public void run() {
try {
socket = new DatagramSocket();
socket.setSoTimeout(3000);//设置超时为3s
} catch (SocketException e) {
Log.i("udpClient","建立接收数据报失败");
e.printStackTrace();
}
packetRcv = new DatagramPacket(msgRcv,msgRcv.length);
while (udpLife){
try {
Log.i("udpClient", "UDP监听");
socket.receive(packetRcv);
String RcvMsg = new String(packetRcv.getData(),packetRcv.getOffset(),packetRcv.getLength());
//将收到的消息发给主界面
Intent RcvIntent = new Intent();
RcvIntent.setAction("udpRcvMsg");
RcvIntent.putExtra("udpRcvMsg", RcvMsg);
MainActivity.context.sendBroadcast(RcvIntent);
Log.i("Rcv",RcvMsg);
}catch (IOException e){
e.printStackTrace();
}
}
Log.i("udpClient","UDP监听关闭");
socket.close();
}
}
至此UDP核心代码全部部署完成,其中包含了少许其他功能, 如发送给主界面消息代码等,不影响,有不需要的可以自行删除。其中如果想发送消息,那么调用其中的send方法即可。
下面则是主界面代码实现,我的实现思路如下(各有各的实现方法,如果您有更好的,如果愿意请告诉我,我十分愿意学习):
MainActivity界面:
Handler类(主要处理UI更新事件)
OnCreate(绑定控件,事件监听,注册BroadcastReceiver等)
MyButtonClick类(处理各按钮事件)
BroadcastReceiver(广播接收器)
至于里面各自类包含的小逻辑,就不多讲了,看demo可以很快便知道如何使用对应了。
话不多说,放码过来:
package jiugaosh.com.udpdemo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Message;
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 android.os.Handler;
import java.lang.ref.WeakReference;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainActivity extends AppCompatActivity {
TextView txt_Recv,txt_Send;
Button btn_CleanRecv,btn_Send,btn_UdpConn,btn_UdpClose;
EditText edit_Send;
private UDPClient client = null;
public static Context context;
private final MyHandler myHandler = new MyHandler(this);
private StringBuffer udpRcvStrBuf=new StringBuffer(),udpSendStrBuf=new StringBuffer();
MyBtnClick myBtnClick = new MyBtnClick();
private class MyHandler extends Handler{
private final WeakReference mActivity;
public MyHandler(MainActivity activity){
mActivity = new WeakReference(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 1:
udpRcvStrBuf.append(msg.obj.toString());
txt_Recv.setText(udpRcvStrBuf.toString());
break;
case 2:
udpSendStrBuf.append(msg.obj.toString());
txt_Send.setText(udpSendStrBuf.toString());
break;
case 3:
txt_Recv.setText(udpRcvStrBuf.toString());
break;
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
bindWidget(); //控件绑定
listening(); //监听事件
bindReceiver();//注册broadcastReceiver接收器
iniWidget(); //初始化控件状态
}
private void bindWidget(){
txt_Recv = (TextView)findViewById(R.id.txt_Recv);
txt_Send = (TextView)findViewById(R.id.txt_Send);
btn_CleanRecv = (Button)findViewById(R.id.btn_CleanRecv);
btn_Send = (Button)findViewById(R.id.btn_Send);
btn_UdpConn = (Button)findViewById(R.id.btn_udpConn);
btn_UdpClose = (Button)findViewById(R.id.btn_udpClose);
edit_Send = (EditText)findViewById(R.id.edit_Send);
}
private void listening(){
btn_Send.setOnClickListener(myBtnClick);
btn_UdpConn.setOnClickListener(myBtnClick);
btn_UdpClose.setOnClickListener(myBtnClick);
btn_CleanRecv.setOnClickListener(myBtnClick);
}
private void bindReceiver(){
IntentFilter udpRcvIntentFilter = new IntentFilter("udpRcvMsg");
registerReceiver(broadcastReceiver,udpRcvIntentFilter);
}
private void iniWidget(){
btn_Send.setEnabled(false);
}
class MyBtnClick implements Button.OnClickListener{
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_CleanRecv:
udpRcvStrBuf.delete(0,udpRcvStrBuf.length());
Message message = new Message();
message.what = 3;
myHandler.sendMessage(message);
break;
case R.id.btn_udpConn:
//建立线程池
ExecutorService exec = Executors.newCachedThreadPool();
client = new UDPClient();
exec.execute(client);
btn_UdpClose.setEnabled(true);
btn_UdpConn.setEnabled(false);
btn_Send.setEnabled(true);
break;
case R.id.btn_udpClose:
client.setUdpLife(false);
btn_UdpConn.setEnabled(true);
btn_UdpClose.setEnabled(false);
btn_Send.setEnabled(false);
break;
case R.id.btn_Send:
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = 2;
if (edit_Send.getText().toString()!=""){
client.send(edit_Send.getText().toString());
message.obj = edit_Send.getText().toString();
myHandler.sendMessage(message);
}
}
});
thread.start();
break;
}
}
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.hasExtra("udpRcvMsg")) {
Message message = new Message();
message.obj = intent.getStringExtra("udpRcvMsg");
message.what = 1;
Log.i("主界面Broadcast","收到"+message.obj.toString());
myHandler.sendMessage(message);
}
}
};
}
当然,不能忘记在AndroidMainFest文件中加上权限,毕竟你是要联网的!
写在最后:实现这些功能其实较为简单,网上有很多成熟且很棒的例子,各位多看多学,必没有问题!其中进制转换其实很简单实现,各位只要对那两个stringbuffer进行进制操作和显示即可!
通信效果请点击上方UDP server最后有图片展示
附上demo:
http://download.csdn.net/detail/shankezh/9442049