Tcp是基于传输层的面向连接的可靠通讯协议,其优点是基于连接,使得服务端和客户端可以实现双向通信,且实时性高,在需要服务端主动向客户端推送数据的应用场景中,使用TCP协议是一种很好的方式。

初学Android,将Android中Tcp的使用方式记录一下,希望对新学Android开发的新同学有帮助,这里主要介绍TcpClient的使用,因为很少会用Android来建立TcpServer端。

这里主要介绍Tcp客户端的几个应用:

1.与服务器建立连接

2.向服务端发送数据

3.接收服务端返回的数据

4.断线重连机制

 

在Android中使用socket有两个地方需要注意的:

1.在AndroidMainfest.xml中需要添加对网络的权限支持

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

2.Android中规定对socket的操作必须在线程中进行,如在主线程中进行操作会出现无法收发数据的情况。

 

(1)创建socket,与服务器建立连接

InetSocketAddress SerAddr = new InetSocketAddress(”192.168.1.100“,9988); //设置服务的IP地址和端口
 
 
try {
        socket.connect(SerAddr,3000);   //尝试连接服务器
    }catch (Exception e){}


(2)发送数据

try {
    
  /注意采用utf-8编码确保中文传输不会乱码
    BufferedWriter bufferedWriter =new BufferedWriter(new OutputStreamWriter( socket.getOutputStream(),"utf-8")); 
     bufferedWriter.write(”Hello“);
     bufferedWriter.flush();
    }catch (Exception e){
}

   
(3)接收数据

try {
    inputStream = new DataInputStream(socket.getInputStream());
    if(inputStream.available()>0)
    {
      byte[] recData = new byte[inputStream.available()];
      inputStream.read(recData);
      String iText=new String(recData,"utf-8");
      }

    }catch (Exception e){
}

(4)断线重连

当保持长时间的连接时,难免会因为网络或其他原因导致客户端与服务端断开连接,所以代码里面应该定时的去检查连接状态,当连接断开时,

应该重新尝试连接服务端。我们这里可以使用socket.sendUrgentData(0xFF);函数来检测,当服务端断开时,连续三次调用此函数会出现异常。

我们可以根据是否出现异常来断定与服务器的连接情况。

try {
    socket.sendUrgentData(0xFF);
}catch (Exception e){
    socket.close();        //关闭套接字,重新创建新的并调用connect函数重新连接
    socket = new Socket();
}

以下贴出TcpHelper类的具体代码:

public class TcpHelper{
    private Socket socket;           
    private BufferedWriter  bufferedWriter;
    private DataInputStream inputStream;
    private boolean NeedStop;
    private InetSocketAddress SerAddr;
    public  String ErrMsg;
    private ReadThread readThread;           //读取数据线程
    private OnReceiveEvent receiveEvent;     //此事件用于当接收到数据时向主线程通知接收到的数据
    private long LastCheckTime;
    public static interface OnReceiveEvent{
        public  void ReceiveBytes(byte[] iData);
        public  void ReceiveString(String iData);
    }
    public enum EDataType{EDT_BYTE,EDT_STRING};
    private EDataType dataType;
    public TcpHelper(String HostIp,int HostPort) {
        try {
            LastCheckTime=System.currentTimeMillis();
            readThread =new ReadThread();
            NeedStop=false;
            SerAddr =  new InetSocketAddress(HostIp,HostPort);
            NeedStop=false;
            socket = new Socket();
            readThread.start();
        }catch (Exception e)
        {
            ErrMsg=e.getMessage();
        }
    }
    public void SendString(String iText){       //发送字符串
        dataType=EDataType.EDT_STRING;
        toSend(iText);
    }
    public void SendBytes(byte[] iBuf){     //发送字节流指令
        dataType=EDataType.EDT_BYTE;
        String iText = new  String(iBuf);
        toSend(iText);
    }
    //发送数据线程
    private void toSend(final String iText){
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        try {
                            bufferedWriter.write(iText);
                            bufferedWriter.flush();
                        } catch (Exception e) {
                        }
                    }
                }
        ).start();
    }
    public boolean isConnected(){
        return socket.isConnected();
    }
    //设置通知事件
    public void setReceiveEvent(OnReceiveEvent iEvent){
        receiveEvent=iEvent;
    }
    //读取线程
    private class ReadThread extends Thread{
        @Override
        public void run() {
            while (!NeedStop){
                try {
                    if (!socket.isConnected() || socket.isClosed()){
                        socket.connect(SerAddr,3000);
                        if(bufferedWriter==null)
                            bufferedWriter =new BufferedWriter(new OutputStreamWriter( socket.getOutputStream(),"utf-8"));
                        if(inputStream==null)
                            inputStream = new DataInputStream(socket.getInputStream());
                    }
                    else {
                        if(inputStream.available()>0){
                            byte[] recData = new byte[inputStream.available()];
                            inputStream.read(recData);
                            if(receiveEvent!=null)
                            {
                                if(dataType==EDataType.EDT_BYTE) {
                                    receiveEvent.ReceiveBytes(recData);
                                }
                                else {
                                    String s=new String(recData,"utf-8");
                                    receiveEvent.ReceiveString(s);
                                }
                            }
                        }
                        if (System.currentTimeMillis()-LastCheckTime>5000)
                        {
                            try {
                                LastCheckTime=System.currentTimeMillis();
                                socket.sendUrgentData(0xFF);
                            }catch (Exception e){
                                socket.close();
                                socket = new Socket();
                                bufferedWriter=null;
                                inputStream =null;
                            }
                        }
                    }

                }catch (Exception e){

                }
            }
        }
    }
}

测试Tcp连接的Activity代码:

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;


public class TcpFormActivity extends Activity {
    private TcpHelper tcpHelper;
    private String SerIp;
    private int SerPort;
    private EditText InputMsg;
    private TextView RecMsg;
    private String TcpRecData;
    private MyHandler handler;
    private TcpReceive tcpReceive;
    @Override
    protected void onCreate(Bundle saveInstanceState){
        super.onCreate(saveInstanceState);
        setContentView(R.layout.activity_tcpform);
        RecMsg = (TextView)findViewById(R.id.TVTcpData);
        InputMsg =  (EditText)findViewById(R.id.EdtTcpMsg);
    }
    public class TcpReceive implements TcpHelper.OnReceiveEvent{
        public  synchronized void ReceiveBytes(byte[] iData){
        }
        public  synchronized  void ReceiveString(String iData){
            TcpRecData=iData;
            Message msg=new Message();
            msg.what=1;
            handler.sendMessage(msg);
        }
    }
    class MyHandler extends Handler {
        public MyHandler() {
        }
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    RecMsg.append(TcpRecData);  //接收到数据显示到TextView上
                    break;
            }
            super.handleMessage(msg);
        }
    }
    public void onConnectClick(View view){
        if(tcpHelper==null)
        {
            SerIp = ((EditText)findViewById(R.id.EdtTcpSerIp)).getText().toString();
            SerPort =Integer.parseInt(((TextView)findViewById(R.id.EdtTcpPort)).getText().toString());
            tcpHelper = new TcpHelper(SerIp,SerPort);
            tcpReceive = new TcpReceive();
            tcpHelper.setReceiveEvent(tcpReceive);
            handler = new MyHandler();
        }
    }
    public void onSendMsgClick(View view){
        try {
            String iText=InputMsg.getText().toString();
            tcpHelper.SendString(iText);
        }catch (Exception e)
        {

        }
    }
}