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代码:
- <?xml version="1.0" encoding="utf-8"?>
- <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:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- android:orientation="vertical"
- android:layout_weight="2"
- tools:context="jiugaosh.com.udpdemo.MainActivity">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:orientation="vertical"
- android:layout_weight="1">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="接收区:" />
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="right"
- android:textSize="8dp"
- android:id="@+id/btn_udpConn"
- android:text="建立连接" />
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="right"
- android:textSize="8dp"
- android:id="@+id/btn_udpClose"
- android:text="关闭连接" />
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="right"
- android:textSize="8dp"
- android:id="@+id/btn_CleanRecv"
- android:text="清除接收区" />
- </LinearLayout>
- <TextView
- android:layout_width="match_parent"
- android:layout_weight="7"
- android:layout_height="0dp"
- android:id="@+id/txt_Recv"
- android:background="@drawable/border"/>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:orientation="horizontal"
- android:layout_weight="2">
- <CheckBox
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="2"
- android:text="Hex显示"/>
- <CheckBox
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="2"
- android:text="二进制显示"/>
- <CheckBox
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="2"
- android:text="十进制显示"/>
- </LinearLayout>
- </LinearLayout>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:orientation="vertical"
- android:layout_weight="1">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:text="发送区:" />
- <TextView
- android:layout_width="match_parent"
- android:layout_weight="7"
- android:background="@drawable/border"
- android:id="@+id/txt_Send"
- android:layout_height="0dp" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:orientation="horizontal"
- android:layout_weight="2">
- <CheckBox
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="2"
- android:text="Hex显示"/>
- <CheckBox
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="2"
- android:text="二进制显示"/>
- <CheckBox
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="2"
- android:text="十进制显示"/>
- </LinearLayout>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:orientation="horizontal"
- android:layout_weight="2">
- <EditText
- android:layout_width="0dp"
- android:layout_weight="5"
- android:id="@+id/edit_Send"
- android:background="@drawable/border"
- android:layout_height="match_parent" />
- <Button
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="match_parent"
- android:layout_gravity="right"
- android:id="@+id/btn_Send"
- android:text="发送"/>
- </LinearLayout>
- </LinearLayout>
- </LinearLayout>
至此我们界面全部完成,我们开始实现对应功能!继续向下看。
首先在写代码前要说明下关键性的几个类,我们完成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<MainActivity> mActivity;
- public MyHandler(MainActivity activity){
- mActivity = new WeakReference<MainActivity>(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);
- }
- }
- };
- }
- <uses-permission android:name="android.permission.INTERNET" />
写在最后:实现这些功能其实较为简单,网上有很多成熟且很棒的例子,各位多看多学,必没有问题!其中进制转换其实很简单实现,各位只要对那两个stringbuffer进行进制操作和显示即可!
通信效果请点击上方UDP server最后有图片展示