Android——Tcp服务端实现

Android——Tcp服务端
        传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
        Tcp分为服务端(网络应用程序)和客户端(网络应用程序),Tcp通信过程,首先打开服务器监听自己的网络通信端口(假设为7628),打开客户端,设置好要连接的ip地址和服务器的网络通信端口(7628),这样服务器监听到网络通信端口有连接,二者就建立了连接。
客户端:可以连接服务端、发送数据、接收数据、关闭连接等。
服务端:可以实现绑定通信端口,接收客户端连接、接收数据、发送数据等。

在java项目中我们可以较为快捷地使用TCP通讯,但想要在Android中使用还有很多要注意的地方。下面我们来学习下Tcp服务端在Android上的实现。

我之前做过一个项目里有个要通过Tcp获取智能手环上电量、心率,血压血氧、步数等基本数据的功能。(这里只是个功能一样的简单小Demo,报文需要处理才能看到想要的信息)

服务端ServerSocket的构造方法:
1、ServerSocket():构造一个新的未绑定的ServerSocket。
2、ServerSocket(int port):构造一个新的ServerSocket并绑定到指定端口,如果port等于0,则端口由系统自动分配。
3、ServerSocket(int port,int backlog):构造一个新的ServerSocket并绑定到指定端口以及指定进入队列的数目。如果port等于0,则端口由系统自动分配。
4、ServerSocket(int port,int backlog,InetAddress localAddress):构造一个新的ServerSocket并绑定到指定端口以及指定进入队列的数目。如果port等于0,则端口由系统自动分配。如果localAddress为null,则可以使用任意地址。


Tcp服务端使用步骤为:

①创建ServerSocket,绑定指定端口

try {
    //开启服务、指定端口号
    socket = new ServerSocket(mServerPort);
} catch (IOException e) {
    e.printStackTrace();
    Toast.makeText(this, "服务开启失败", Toast.LENGTH_SHORT).show();
    return;
}

②调用ServerSocket的accept(),监听连接请求

③调用Socket类中的getInputStream()和getOutputStream()获取输入输出流

class SocketAcceptThread extends Thread {
    @Override
    public void run() {
        try {
            //等待客户端的连接,Accept会阻塞,直到建立连接,
            //所以需要放在子线程中运行。
            mSocket = socket.accept();
            //获取输入流
            mInStream = mSocket.getInputStream();
            //获取输出流
            mOutStream = mSocket.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
            startAccept();
            return;
        }
        Log.i(TAG, "accept success");
        SocketReceive();
    }
}

 

​​​​​​​ ④接收、发送数据

/**
 * 发送
 */
private void sendText() {
    if (mSocket == null) {
        Toast.makeText(MainActivity.this, "没有客户端连接", Toast.LENGTH_LONG).show();
        return;
    }
    String str = content.getText().toString();
    if (str.length() == 0) {
        return;
    }
    Message msg = new Message();
    msg.what = Two;
    msg.obj = str;
    mSubThreadHandler.sendMessage(msg);
}

private void writeMsg(String msg) {
    if (msg.length() == 0 || mOutStream == null) {
        return;
    }
    try {
        //发送
        mOutStream.write(msg.getBytes());
        mOutStream.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
int count = mInStream.read(buffer);

 ⑤关闭服务

if (socket != null) {
    try {
        socket.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

注意: 在清单文件中添加权限

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

下面是MainActivity.java完整代码 :

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    /**
     * 设置
     */
    private Button setting;
    /**
     * 开启服务
     */
    private Button open_service;
    /**
     * 输入内容
     */
    private EditText content;
    /**
     * 发送
     */
    private Button send_out;
    /**
     * 接收到的数据
     */
    private EditText receive;
    private final String TAG = "MainActivity";
    private static final char HexCharArr[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    /**
     * 服务端端口
     */
    private int mServerPort;
    private SharedPreferences sp;
    private static final String PORT = "port";
    public Socket mSocket;
    private HandlerThread mHandlerThread;
    /**
     * 子线程中的Handler实例
     */
    private Handler mSubThreadHandler;
    private SocketAcceptThread mAcceptThread;
    private SocketReceiveThread mReceiveThread;
    private ServerSocket socket;
    /**
     * 输出流
     */
    private OutputStream mOutStream;
    /**
     * 输入流
     */
    private InputStream mInStream;
    private static final int One = 1;
    private static final int Two = 2;
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case One:
                    String sb = receive.getText().toString() + "\r\n" + (String) msg.obj;
                    receive.setText(sb);
                    break;
                default:
                    break;
            }
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setting = findViewById(R.id.setting);
        open_service = findViewById(R.id.open_service);
        content = findViewById(R.id.content);
        send_out = findViewById(R.id.send_out);
        receive = findViewById(R.id.receive);
        setting.setOnClickListener(this);
        open_service.setOnClickListener(this);
        send_out.setOnClickListener(this);
        //获取sharedPreferences对象
        sp = getSharedPreferences("settings", Context.MODE_PRIVATE);
        //如果key不存在,则返回默认defValue
        mServerPort = sp.getInt(PORT, 7628);
        initHandlerThraed();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestory");
        closeConnect();
        if (socket != null) {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void closeConnect() {
        try {
            if (mOutStream != null) {
                mOutStream.close();
            }
            if (mInStream != null) {
                mInStream.close();
            }
            if (mSocket != null) {
                mSocket.close();    //关闭socket
                mSocket = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (mReceiveThread != null) {
            mReceiveThread.threadExit();
            mReceiveThread = null;
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            //设置
            case R.id.setting:
                set();
                break;
            //开启服务
            case R.id.open_service:
                startServer();
                break;
            //发送
            case R.id.send_out:
                sendText();
                break;
            default:
                break;
        }
    }

    /**
     * 设置
     */
    private void set() {
        //获取布局
        View setview = LayoutInflater.from(this).inflate(R.layout.port, null);
        //获取布局中的控件
        final EditText editport = (EditText) setview.findViewById(R.id.server_port);
        Button ensureBtn = (Button) setview.findViewById(R.id.server_ok);
        editport.setText(sp.getInt(PORT, 7628) + "");

        final android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(this);
        //设置dialog显示一个view
        builder.setView(setview);
        //dialog显示
        final AlertDialog dialog = builder.show();
        ensureBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String port = editport.getText().toString();
                if (port != null && port.length() > 0) {
                    mServerPort = Integer.parseInt(port);//将内容转换成整数
                }
                SharedPreferences.Editor editor = sp.edit(); //SharedPreferences.Editor 简单的数据存储
                editor.putInt(PORT, mServerPort);   //存储数据
                editor.commit();                    //提交
                dialog.dismiss();                   //dialog消失
            }
        });
    }

    /**
     * 开启服务
     */
    void startServer() {
        try {
            //开启服务、指定端口号
            socket = new ServerSocket(mServerPort);
        } catch (IOException e) {
            e.printStackTrace();
            Toast.makeText(this, "服务开启失败", Toast.LENGTH_SHORT).show();
            return;
        }
        startAccept();
        Toast.makeText(this, "服务开启", Toast.LENGTH_LONG).show();
    }

    /**
     * 开启SocketAcceptThread()线程
     */
    private void startAccept() {
        mAcceptThread = new SocketAcceptThread();
        mAcceptThread.start();
    }

    class SocketAcceptThread extends Thread {
        @Override
        public void run() {
            try {
                //等待客户端的连接,Accept会阻塞,直到建立连接,
                //所以需要放在子线程中运行。
                mSocket = socket.accept();
                //获取输入流
                mInStream = mSocket.getInputStream();
                //获取输出流
                mOutStream = mSocket.getOutputStream();
            } catch (IOException e) {
                e.printStackTrace();
                startAccept();
                return;
            }
            Log.i(TAG, "accept success");
            SocketReceive();
        }
    }

    private void SocketReceive() {
        mReceiveThread = new SocketReceiveThread();
        mReceiveThread.start();
    }

    class SocketReceiveThread extends Thread {
        private boolean threadExit = false;

        @Override
        public void run() {
            byte[] buffer = new byte[1024];
            while (threadExit == false) {
                try { //读取数据,返回值表示读到的数据长度。-1表示结束
                    int count = mInStream.read(buffer);
                    if (count == -1) {
                        Log.i(TAG, "read read -1");
                        startAccept();
                        break;
                    } else {
                        String receiveData;
                        receiveData = byteArrToHex(buffer);
                        Log.i(TAG, "read buffer:" + receiveData + ",count=" + count);
                        Message msg = new Message();
                        msg.what = One;
                        msg.obj = receiveData;

                        mHandler.sendMessage(msg);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        void threadExit() {
            threadExit = true;
        }
    }

    /**
     * 发送
     */
    private void sendText() {
        if (mSocket == null) {
            Toast.makeText(MainActivity.this, "没有客户端连接", Toast.LENGTH_LONG).show();
            return;
        }
        String str = content.getText().toString();
        if (str.length() == 0) {
            return;
        }
        Message msg = new Message();
        msg.what = Two;
        msg.obj = str;
        mSubThreadHandler.sendMessage(msg);
    }

    private void writeMsg(String msg) {
        if (msg.length() == 0 || mOutStream == null) {
            return;
        }
        try {
            //发送
            mOutStream.write(msg.getBytes());
            mOutStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 字节数组转换十六进制
     */
    public static String byteArrToHex(byte[] btArr) {
        char strArr[] = new char[btArr.length * 2];
        int i = 0;
        for (byte bt : btArr) {
            strArr[i++] = HexCharArr[bt >>> 4 & 0xf];
            strArr[i++] = HexCharArr[bt & 0xf];
        }
        return new String(strArr);
    }

    private void initHandlerThraed() {
        //创建HandlerThread实例
        mHandlerThread = new HandlerThread("handler_thread");
        //开始运行线程
        mHandlerThread.start();
        //获取HandlerThread线程中的Looper实例
        Looper loop = mHandlerThread.getLooper();
        //创建Handler与该线程绑定。
        mSubThreadHandler = new Handler(loop) {
            @Override
            public void handleMessage(Message msg) {
                Log.i(TAG, "mSubThreadHandler handleMessage thread:" + Thread.currentThread());
                switch (msg.what) {
                    case Two:
                        writeMsg((String) msg.obj);
                        break;
                    default:
                        break;
                }
            }
        };
    }

}

 

最后是运行效果:设置端口、开启服务、获取的数据(需要处理)

 

 

 Demo中用到的Handlerdialog对话框SharedPreferences不理解的可以参考一下我之前的发布的文章。

  • 6
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
要在Android Studio中建立TCP连接服务器,首先需要确保你已经有了一个可用的服务器端程序,可以接受TCP连接。接着,在Android应用中使用Java代码编写一个TCP客户端,来连接服务器。 首先,在Android Studio中创建一个新的项目,然后在项目中创建一个新的类来实现TCP连接功能。在该类中,你需要使用Socket类来创建一个套接字对象, 并指定要连接的服务器的IP地址和端口号。然后使用该套接字对象的输入输出流来发送和接收数据。 要在Android应用中建立TCP连接,需要在AndroidManifest.xml文件中添加Internet权限。这可以通过在<manifest>标签中添加<uses-permission>标签,并指定android.permission.INTERNET权限来实现。 在建立连接之后,你可以使用输入输出流来发送和接收数据。发送数据可以通过使用输出流的write()方法,接收数据可以通过使用输入流的read()方法。在读写数据之后,记得关闭连接以释放资源。 另外,为了避免在主线程中进行网络操作导致应用无响应,建议使用AsyncTask或者线程池来进行网络操作。这样可以在后台线程中进行网络连接,而不会影响主线程的UI响应。 总之,使用Android Studio建立TCP连接服务器需要通过Socket类创建套接字对象,使用输入输出流进行数据传输,并在合适的地方添加Internet权限以及合适的线程管理来确保应用稳定运行。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值