Android tcp Socket

table of Contents:

       1. Tools (1) TcpClient

       2. Tools (two) SocketTransceiver

       3. Use in activity:

 

Tools (1) TcpClient

import java.net.InetAddress;
import java.net.Socket;

/**
 *  * TCP Socket客户端
 *  * 
 *  
 */
public abstract class TcpClient implements Runnable {

    
    private int port;
    
    private String hostIP;
    
    private boolean connect = false;
    
    private SocketTransceiver transceiver;

    /**
      * 建立连接
      * <p>
      * 连接的建立将在新线程中进行
      * <p>
      * 连接建立成功,回调{@code onConnect()}
      * <p>
      * 连接建立失败,回调{@code onConnectFailed()}
      * 
      * @param hostIP
      *            服务器主机IP
      * @param port
      *            端口
      */
            

    public void connect(String hostIP, int port) {
        this.hostIP = hostIP;
        this.port = port;
        new Thread(this).start();
    }

    
    @Override
    

    public void run() {
        try {
            Socket socket = new Socket(hostIP, port);
            transceiver = new SocketTransceiver(socket) {

                @Override
                

                public void onReceive(InetAddress addr, String s) {
                    TcpClient.this.onReceive(this, s);
                }

                @Override
                

                public void onDisconnect(InetAddress addr) {
                    connect = false;
                    TcpClient.this.onDisconnect(this);
                }
            
            };
            transceiver.start();
            connect = true;
            this.onConnect(transceiver);
        } catch (Exception e) {
            e.printStackTrace();
            this.onConnectFailed();
        }
    }

    /**
      * 断开连接
      * <p>
      * 连接断开,回调{@code onDisconnect()}
      */
            

    public void disconnect() {
        if (transceiver != null) {
            transceiver.stop();
            transceiver = null;
        }
    }

    /**
      * 判断是否连接
      * 
      * @return 当前处于连接状态,则返回true
      */
            

    public boolean isConnected() {
        return connect;
    }

    /**
      * 获取Socket收发器
      * 
      * @return 未连接则返回null
      */
            

    public SocketTransceiver getTransceiver() {
        return isConnected() ? transceiver : null;
    }

    /**
      * 连接建立
      * 
      * @param transceiver
      *            SocketTransceiver对象
      */
            

    public abstract void onConnect(SocketTransceiver transceiver);

    /**
      * 连接建立失败
      */
            

    public abstract void onConnectFailed();

    /**
      * 接收到数据
      * <p>
      * 注意:此回调是在新线程中执行的
      * 
      * @param transceiver
      *            SocketTransceiver对象
      * @param s
      *            字符串
      */
            

    public abstract void onReceive(SocketTransceiver transceiver, String s);

    /**
      * 连接断开
      * <p>
      * 注意:此回调是在新线程中执行的
      * 
      * @param transceiver
      *            SocketTransceiver对象
      */
            

    public abstract void onDisconnect(SocketTransceiver transceiver);
}

Tools (two) SocketTransceiver

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;

/**
 *  * Socket收发器 通过Socket发送数据,并使用新线程监听Socket接收到的数据
 *  * 
 *  * @author jzj1993
 *  * @since 2015-2-22
 *  
 */
public abstract class SocketTransceiver implements Runnable {

    
    protected Socket socket;
    
    protected InetAddress addr;
    
    protected DataInputStream in;
    
    protected DataOutputStream out;
    
    private boolean runFlag;

    /**
      * 实例化
      * 
      * @param socket
      *            已经建立连接的socket
      */
            

    public SocketTransceiver(Socket socket) {
        this.socket = socket;
        this.addr = socket.getInetAddress();
    }

    /**
      * 获取连接到的Socket地址
      * 
      * @return InetAddress对象
      */
            

    public InetAddress getInetAddress() {
        return addr;
    }

    /**
      * 开启Socket收发
      * <p>
      * 如果开启失败,会断开连接并回调{@code onDisconnect()}
      */
            

    public void start() {
        runFlag = true;
        new Thread(this).start();
    }

    /**
      * 断开连接(主动)
      * <p>
      * 连接断开后,会回调{@code onDisconnect()}
      */
            

    public void stop() {
        runFlag = false;
        try {
            socket.shutdownInput();
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
      * 发送字符串
      * 
      * @param s
      *            字符串
      * @return 发送成功返回true
      */
            

    public boolean send(String s) {
        if (out != null) {
            try {
                out.writeUTF(s);
                out.flush();
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    /**
      * 监听Socket接收的数据(新线程中运行)
      */
            
    @Override
    

    public void run() {
        try {
            in = new DataInputStream(this.socket.getInputStream());
            out = new DataOutputStream(this.socket.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
            runFlag = false;
        }
        while (runFlag) {
            try {
                final String s = in.readUTF();
                this.onReceive(addr, s);
            } catch (IOException e) {
                // 连接被断开(被动)
                runFlag = false;
            }
        }
        // 断开连接
        try {
            in.close();
            out.close();
            socket.close();
            in = null;
            out = null;
            socket = null;
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.onDisconnect(addr);
    }

    /**
      * 接收到数据
      * <p>
      * 注意:此回调是在新线程中执行的
      * 
      * @param addr
      *            连接到的Socket地址
      * @param s
      *            收到的字符串
      */
            

    public abstract void onReceive(InetAddress addr, String s);

    /**
      * 连接断开
      * <p>
      * 注意:此回调是在新线程中执行的
      * 
      * @param addr
      *            连接到的Socket地址
      */
            

    public abstract void onDisconnect(InetAddress addr);
}

Three, the use of activity:

public class MainActivity extends Activity implements OnClickListener {

    private Button bnConnect;
    private TextView txReceive;
    private EditText edIP, edPort, edData;

    private Handler handler = new Handler(Looper.getMainLooper());

    private TcpClient client = new TcpClient() {

        @Override
        public void onConnect(SocketTransceiver transceiver) {
            refreshUI(true);
        }

        @Override
        public void onDisconnect(SocketTransceiver transceiver) {
            refreshUI(false);
        }

        @Override
        public void onConnectFailed() {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(MainActivity.this, "连接失败",
                            Toast.LENGTH_SHORT).show();
                }
            });
        }

        @Override
        public void onReceive(SocketTransceiver transceiver, final String s) {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    txReceive.append(s);
                }
            });
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        this.findViewById(R.id.bn_send).setOnClickListener(this);
        bnConnect = (Button) this.findViewById(R.id.bn_connect);
        bnConnect.setOnClickListener(this);

        edIP = (EditText) this.findViewById(R.id.ed_ip);
        edPort = (EditText) this.findViewById(R.id.ed_port);
        edData = (EditText) this.findViewById(R.id.ed_dat);
        txReceive = (TextView) this.findViewById(R.id.tx_receive);
        txReceive.setOnClickListener(this);

        refreshUI(false);
    }

    @Override
    public void onStop() {
        client.disconnect();
        super.onStop();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bn_connect:
                connect();
                break;
            case R.id.bn_send:
                sendStr();
                break;
            case R.id.tx_receive:
                clear();
                break;
        }
    }

    /**
     * 刷新界面显示
     *
     * @param isConnected
     */
    private void refreshUI(final boolean isConnected) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                edPort.setEnabled(!isConnected);
                edIP.setEnabled(!isConnected);
                bnConnect.setText(isConnected ? "断开" : "连接");
            }
        });
    }

    /**
     * 设置IP和端口地址,连接或断开
     */
    private void connect() {
        if (client.isConnected()) {
            // 断开连接
            client.disconnect();
        } else {
            try {
                String hostIP = edIP.getText().toString();
                int port = Integer.parseInt(edPort.getText().toString());
                client.connect(hostIP, port);
            } catch (NumberFormatException e) {
                Toast.makeText(this, "端口错误", Toast.LENGTH_SHORT).show();
                e.printStackTrace();
            }
        }
    }

    /**
     * 发送数据
     */
    private void sendStr() {
        try {
            String data = edData.getText().toString();
            client.getTransceiver().send(data);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 清空接收框
     */
    private void clear() {
        new AlertDialog.Builder(this).setTitle("确认清除?")
                .setNegativeButton("取消", null)
                .setPositiveButton("确认", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        txReceive.setText("");
                    }
                }).show();
    }
}

Guess you like

Origin blog.csdn.net/qq_36355271/article/details/98956897