• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
MKT-porter
博客园    首页    新随笔    联系   管理    订阅  订阅
1 TCP/IP通信

重点参考长链接http://blog.csdn.net/fengyuzhengfan/article/details/38830115

http://blog.csdn.net/Jsagacity/article/details/78531819#

http://www.runoob.com/w3cnote/android-tutorial-socket1.html

 

 

 

 

1 电脑(或ESP8266)连接WIFI,建立服务 192.168.3.8  8080

1.1 查看电脑地址

1.2 电脑建立服务 192.168.3.8  8080

2 手机连接WIFI,创建客户申请服务 

手机在wifi 下分配的地址是 192.168.3.9 

2.1 手机打开软件

 

 

点击发送

电脑接收

 

2手机端工程

 手机端分为两个工程

1短链接。发送完消息就自动断开。不牵扯链接中断问题,但无法接收消息。

2长连接。发送完消息还可以接收消息。实现数据互传,但是还没有加入重链接功能。

 

2.1 AsyncTask建立的短链接

1 布局管理

 

 

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.dongdong.myapplication.MainActivity">


    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/LinearLayout1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical"
        tools:context=".MainActivity"
        android:weightSum="1">

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center"
            android:weightSum="1">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="IP:"
                android:layout_weight="0.04" />
            <EditText
                android:id="@+id/SIP"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="0.65" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="端口:"/>
            <EditText
                android:id="@+id/IPort"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="0.17" />

        </LinearLayout>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="left"
        android:weightSum="1">
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="连接"/>

        <Button
            android:id="@+id/bt_send"
            android:layout_width="88dp"
            android:layout_height="wrap_content"
            android:text="发送"
            android:layout_below="@+id/tv_content"
            android:layout_alignParentStart="true"
            tools:layout_editor_absoluteY="0dp"
            tools:layout_editor_absoluteX="8dp" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="清空"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:gravity="left"
        android:weightSum="1">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="发送区:"
            android:layout_weight="0.04" />

        <EditText
            android:id="@+id/sentText"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/tv_send_text"
            android:layout_width="241dp"
            android:layout_height="43dp"

            android:text="发送的内容"
            android:layout_below="@+id/bt_send"
            tools:layout_editor_absoluteX="8dp"
            tools:layout_editor_absoluteY="8dp"

            android:layout_weight="0.03" />
    </LinearLayout>
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:gravity="left"
        android:weightSum="1"
        android:layout_weight="0.12">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="接收区:"
            />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="清空"/>
        <TextView
            android:id="@+id/tv_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            android:gravity="left"
            android:text="接收的内容"
            android:layout_alignParentTop="true"
            android:layout_alignParentStart="true"
            tools:layout_editor_absoluteY="0dp"
            tools:layout_editor_absoluteX="8dp" />
    </LinearLayout>
    </LinearLayout>

</android.support.constraint.ConstraintLayout>

  

  

  2 添加网络权限

 

<uses-permission android:name="android.permission.INTERNET"/>  

  

  3 工程目录

1采用AsyncTask 异步模式

 输入参数问题

2.1  函数输入参数1可以设置输入参数,可以是控件

  SendAsyncTask myTask = new SendAsyncTask(SIP_target,IPort__target);     

2.2 

   myTask.execute(str);

对应这个参数是

doInBackground(String... params) 

 

  

package com.example.dongdong.myapplication;


import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

import android.view.View;
import android.view.View.OnClickListener;

import android.widget.TextView;
import android.widget.EditText;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements OnClickListener {

  //  1.1 定义
    private Button bt_send;
    private TextView tv_content;
    private TextView tv_send_text;

    private EditText SIP;
    private EditText IPort;
    private EditText sentText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
         // 1.2 控件初始化
        InitView();
        //  2 开启服务器
        MobileServer mobileServer = new MobileServer();
        mobileServer.setHandler(handler);
        new Thread(mobileServer).start();

    }

    private void InitView() {
        tv_content = (TextView) findViewById(R.id.tv_content);
        tv_send_text = (TextView) findViewById(R.id.tv_send_text);

        sentText=(EditText) findViewById(R.id.sentText);
        SIP=(EditText) findViewById(R.id.SIP);
        IPort=(EditText) findViewById(R.id.IPort);

        bt_send = (Button) findViewById(R.id.bt_send);
        bt_send.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bt_send:
               // String str = "Sent to the ESP8266";
                String str="请输入命令";
                int IPort__target=8080;
                String  SIP_target="192.168.1.1";
               if( sentText!=null)
               {
                   str=sentText.getText().toString().trim();
               }
                if (SIP!= null) {
                    SIP_target=SIP.getText().toString().trim();

                }
                if (IPort!= null) {
                    String msg = IPort.getText().toString().trim();
                    if (msg != null && msg.length() > 0) {
                        IPort__target = Integer.parseInt(msg);
                    }
                }
                // 链接IP
                SendAsyncTask myTask = new SendAsyncTask(SIP_target,IPort__target);
                //SendAsyncTask myTask = new SendAsyncTask();
                // 初始发送的消息
                myTask.execute(str);

                tv_send_text.setText(str);
                break;
        }

    }

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    tv_content.setText("WiFi模块发送的:" + msg.obj);
                    Toast.makeText(MainActivity.this, "接收到信息", Toast.LENGTH_LONG)
                            .show();
            }
        }
    };
}

  

  

  

package com.example.dongdong.myapplication;

import java.io.IOException;

import java.net.ServerSocket;
import java.net.Socket;

import java.io.DataInputStream;

import android.os.Handler;
import android.os.Message;

public class MobileServer implements Runnable {
    private ServerSocket server;
    private DataInputStream in;
    private byte[] receice;

    private Handler handler = new Handler();

    public MobileServer() {
    }

    public void setHandler(Handler handler) {
        this.handler = handler;
    }

    @Override
    public void run() {

        try {
            //5000是手机端开启的服务器的端口号,ESP8266进行TCP连接时使用的端口,而IP也是通过指令查询的联入设备的IP
            server = new ServerSocket(5000);
            while (true) {
                Socket client = server.accept();
                in = new DataInputStream(client.getInputStream());
                receice = new byte[50];
                in.read(receice);
                in.close();

                Message message = new Message();
                message.what = 1;
                message.obj = new String(receice);
                handler.sendMessage(message);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            server.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

  

package com.example.dongdong.myapplication;

import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import android.os.AsyncTask;



public class SendAsyncTask extends AsyncTask<String, Void, Void> {
   // public class SendAsyncTask extends AsyncTask<String, Void, Void> {

    //这里是连接ESP8266的IP和端口号,IP是通过指令在单片机开发板查询到,而端口号可以自行设置,也可以使用默认的,333就是默认的
    private  static String IP ;
    private  static int PORT ;

    private Socket client = null;
    private PrintStream out = null;

   public SendAsyncTask(String ip,int port)
   {
      super();
       this.IP = ip;
       this.PORT = port;    }

    @Override
    protected Void doInBackground(String... params) {
        String str = params[0];
        try {
            client = new Socket(IP, PORT);
            client.setSoTimeout(5000);
            // 获取Socket的输出流,用来发送数据到服务端
            out = new PrintStream(client.getOutputStream());
            out.print(str);
            out.flush();

            if (client == null) {
                return null;
            } else {
                out.close();
                client.close();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

}

2 Handler 建立的长连接

功能描述

  1. 建立长链接,链接按钮建立链接 ,发射按钮发射信号,停止按钮结束。也可以改成短链接,生成类的时候把信号加进去。
  2. 界面和通信线程各自有访问彼此的Handler,从而实现数据线程互传互传。
  3. 主界面之外,建立通信线程发送消息。通信线程里又新建一个线程,用于专门接收服务器的数据。

现有问题

  1. 若连超时异常处理
  2. 若连接上但之后中断,连接重检测问题。

工程代码

如果自己新建工程要加入这些代码,注意修改工程名字。一般每个文件的第一行,只一句根据实际建立的工程确定。

 

 

 2.1 网路权限

 

  <uses-permission android:name="android.permission.INTERNET"/>  

 添加后完成整的代码

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.espressif.myapplication">
    <uses-permission android:name="android.permission.INTERNET"/>  
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

  

 

2 布局文件

 

 

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
   >


    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/LinearLayout1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical"
        tools:context=".MainActivity"
        android:weightSum="1">

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center"
            android:weightSum="1">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="IP:"
                android:layout_weight="0.04" />
            <EditText
                android:id="@+id/SIP"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="0.65"
                android:text="192.168.1.102"
                />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="端口:"/>
            <EditText
                android:id="@+id/IPort"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="0.17"
                android:text="8080"
                />

        </LinearLayout>

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="left"
            android:weightSum="1">
            <Button
                android:id="@+id/bt_connect"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="连接"/>

            <Button
                android:id="@+id/bt_send"
                android:layout_width="88dp"
                android:layout_height="wrap_content"
                android:text="发送"
                android:layout_below="@+id/tv_content"
                android:layout_alignParentStart="true"
                tools:layout_editor_absoluteY="0dp"
                tools:layout_editor_absoluteX="8dp" />

            <Button
                android:id="@+id/bt_stop"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text=""/>
        </LinearLayout>

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:gravity="left"
            android:weightSum="1">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="发送区:"
                android:layout_weight="0.04" />

            <EditText
                android:id="@+id/sentText"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" />

            <TextView
                android:id="@+id/tv_send_text"
                android:layout_width="241dp"
                android:layout_height="43dp"

                android:text="发送的内容"
                android:layout_below="@+id/bt_send"
                tools:layout_editor_absoluteX="8dp"
                tools:layout_editor_absoluteY="8dp"

                android:layout_weight="0.03" />
        </LinearLayout>
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:gravity="left"
            android:weightSum="1"
            android:layout_weight="0.12">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="接收区:"
                />
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="清空"/>
            <TextView
                android:id="@+id/tv_content"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"

                android:gravity="left"
                android:text="接收的内容"
                android:layout_alignParentTop="true"
                android:layout_alignParentStart="true"
                tools:layout_editor_absoluteY="0dp"
                tools:layout_editor_absoluteX="8dp" />
        </LinearLayout>
    </LinearLayout>

</android.support.constraint.ConstraintLayout>

 

3 工程文件 

package com.espressif.myapplication;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

import android.view.View;
import android.view.View.OnClickListener;

import android.widget.TextView;
import android.widget.EditText;
import android.widget.Button;
import android.widget.Toast;


public class MainActivity extends AppCompatActivity  implements OnClickListener  {
    //  1.1 定义
    private Button bt_connect;// 链接
    private Button send;// 发送
    private Button bt_stop; //停止

    public TextView tv_content; // 显示接收的命令
    private TextView tv_send_text;  // 显示发送的命令

    private EditText SIP; //IP地址
    private EditText IPort; //端口
    private EditText sentText; // 发送内容
    // 1.2 定义与服务器通信的子线程
    boolean isConnect=true;//连接还是断开
    ClientThread clientThread;
    Handler handler;

    // 2 主函数
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 2.1 控件初始化
        InitView();



    }

// 1 界面控件初始化
    private void InitView() {
        tv_content = (TextView) findViewById(R.id.tv_content);
        tv_send_text = (TextView) findViewById(R.id.tv_send_text);

        sentText=(EditText) findViewById(R.id.sentText);
        SIP=(EditText) findViewById(R.id.SIP);
        IPort=(EditText) findViewById(R.id.IPort);

        send = (Button) findViewById(R.id.bt_send);
        send.setOnClickListener(this);

        bt_connect=(Button) findViewById(R.id.bt_connect);
        bt_connect.setOnClickListener(this);
        bt_stop = (Button) findViewById(R.id.bt_stop);
        bt_stop.setOnClickListener(this);

        // 2.2 用于和主界面通信
        handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case 0x123:
                        tv_content.setText("WiFi模块发送的:" + msg.obj.toString());
                        //  tv_content.append("\n" + msg.obj.toString());
                        break;
                }
            }
        };

    }
// 2 链接TCP/IP 链接目标服务
    public void connectIP(){

        int IPort__target=8080;
        String  SIP_target="192.168.1.1";


        if (SIP!= null) {
            SIP_target=SIP.getText().toString().trim();

        }
        if (IPort!= null) {
            String msg = IPort.getText().toString().trim();
            if (msg != null && msg.length() > 0) {
                IPort__target = Integer.parseInt(msg);
            }
        }


        //  2 开启服务器
        if (isConnect == true) //标志位 = true表示连接
        {

            // 链接IP

            clientThread = new ClientThread(handler);
            clientThread.setip_port(SIP_target, IPort__target);
            new Thread(clientThread).start();

            if(clientThread.isConnect==false){
          //  if(clientThread.s.isConnected()&& !clientThread.s.isClosed()){
                isConnect = true;//置为true
                bt_connect.setText("连接");//按钮上显示连接

            }
            else{
                isConnect = false;//置为false
                bt_connect.setText("断开");//按钮上显示--断开
            }
        }
        else //标志位 = false表示退出连接
        {
            isConnect = true;//置为true
            bt_connect.setText("连接");//按钮上显示连接
            clientThread.stop_connect();
            }
    }
// 3 发送信息
    public void Sendmsg(){

        String msg="1123";
        if( sentText!=null)
        {
            msg=sentText.getText().toString();
        }
        //更新文本框
        tv_send_text.setText(msg);
        // 发送函数
        try {
            Message msga = new Message();
            msga.what = 0x345;
            msga.obj = sentText.getText().toString();
            clientThread.revHandler.sendMessage(msga);

        }
        catch (Exception e)
        {
            e.printStackTrace();
            tv_send_text.setText("发送失败!");
        }



    }

 // 4 按键点击触发器
    @Override
    public void onClick(View v) {
        switch (v.getId()) {

            //1链接函数
            case R.id.bt_connect:
                connectIP();
                break;

            //2 发送信息
            case R.id.bt_send:
                Sendmsg();
                break;
            // 停止
            case R.id.bt_stop:
             // 停止函数
                break;
        }
    }

    }

  

package com.espressif.myapplication;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;

import java.net.SocketTimeoutException;

public class ClientThread implements Runnable
{
    private  static  int Port_target;
    private  static  String IP_target;
    boolean isConnect=true;//连接还是断开
    public Socket s;
    // 该线程所处理的Socket所对应的输入流
    BufferedReader br =null;
    // 输出
    OutputStream os =null;

    // 定义向UI线程发送消息的Handler对象
    private Handler handler;
    // 定义接收UI线程的消息的Handler对象
    public Handler revHandler;



 // 2.1设置通线程向主界面通信对象
public ClientThread(Handler handler) {
        this.handler = handler;   // 定义向UI线程发送消息的Handler对象
}

// 2.2设置链接地址
public void setip_port(String IP,int port){
       IP_target=IP;
      Port_target=port;
 }
 // 2.3从服务器接收信息线程
public void connectthread(){
    // 启动一条子线程来读取服务器响应的数据
    new Thread()
    {  String content =null;
        @Override
        public void run()
        {
            // 不断读取Socket输入流中的内容。
            try
            {
                while ((content = br.readLine())!=null)
                {
                    // 每当读到来自服务器的数据之后,发送消息通知程序界面显示该数据
                    Message msg =new Message();
                    msg.what = 0x123;
                    msg.obj = content;
                    handler.sendMessage(msg);
                }
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }.start();

}
//  2.4将接收命令更新主界面显示框
    public void fruh_UI(){

        // 为当前线程初始化Looper
        Looper.prepare();
        // 创建revHandler对象
        revHandler =new Handler()
        {
            @Override
            public void handleMessage(Message msg)
            {
                // 接收到UI线程中用户输入的数据
                if (msg.what == 0x345)
                {
                    // 将用户在文本框内输入的内容写入网络
                    try
                    {
                        os.write((msg.obj.toString() + "\r\n")
                                .getBytes("utf-8"));
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();
                    }
                }
            }
        };
        // 启动Looper
        Looper.loop();
    }

 // 2.4终止链接
public void stop_connect(){
        try
        {

                isConnect = false;
                s.close();//关闭连接
                s = null;

        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

 public void run()
    {byte[] acceptdata1=null;
        try
        {
            s =new Socket(IP_target, Port_target);
            if(s.isConnected()&& !s.isClosed()){isConnect=true;}
            // 接收数据
            br =new BufferedReader(new InputStreamReader( s.getInputStream()));
            //存放数据
            os =s.getOutputStream();

            // 新线程 接收数据
            connectthread();
            // 更新主界面显示框
            fruh_UI();

       }
       catch (SocketTimeoutException e1)
       {  isConnect=false;
         System.out.println("网络连接超时!!");
       }
       catch (Exception e)
       {
          e.printStackTrace();
       }
    }
}

  

 

 

 

 

posted on 2018-02-03 21:10  MKT-porter  阅读(459)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3