关闭

【Android Socket专题】: TCP通信服务器端app的demo的实现

标签: androidtcpsocket服务器
1701人阅读 评论(0) 收藏 举报
分类:

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

----这篇实现以下TCP 服务器,另外由于实在不是想在重复工作了,所以关于tcp多连接服务器代码直接提供思路放在这边了,单一使用请自行删除和移位相关代码即可,原理是一样的,实现方法也有很多种,个人这里只实现其中一种。


首先规划一下页面:



附上对应XML代码:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="5"
    >

    <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"
            android:orientation="horizontal">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="本机ip:"/>
            <TextView
                android:layout_width="0dp"
                android:layout_weight="2"
                android:layout_height="match_parent"
                android:gravity="center"
                android:id="@+id/txt_Server_Ip"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="port"/>

            <EditText
                android:id="@+id/edit_Server_Port"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:hint="1234"
                android:inputType="number" />
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:orientation="horizontal"
            android:layout_weight="1">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="ID(英文或数字):"/>
            <EditText
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="match_parent"
                android:id="@+id/edit_Server_ID"/>
            <Button
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:text="随机生成"
                android:id="@+id/btn_tcpServerRandomID"/>
        </LinearLayout>

    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="开启"
            android:id="@+id/btn_tcpServerConn"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="关闭"
            android:id="@+id/btn_tcpServerClose"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="清除接收区"
            android:id="@+id/btn_tcpCleanServerRecv"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="清除发送区"
            android:id="@+id/btn_tcpCleanServerSend"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:orientation="vertical"
        android:layout_weight="2">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:gravity="bottom"
            android:text="接收区:" />
        <TextView
            android:layout_width="match_parent"
            android:layout_weight="5"
            android:layout_height="0dp"
            android:id="@+id/txt_ServerRcv"
            android:background="@android:color/holo_blue_light"
            />

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:orientation="vertical"
        android:layout_weight="2">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:text="发送区:" />

        <TextView
            android:id="@+id/txt_ServerSend"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="7"
            android:background="@android:color/holo_purple" />

        <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: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_tcpServerSend"
                android:text="发送"/>
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

界面规划完成,其中关于随机ID这块我没有写代码,有空再补了;

实现TCP 服务器端的关键类在于以下几个类:

1、ServerSocket;

2、Socket;

3、InputSteam;

4、OutputSteam;

5、PrintWriter;

不懂得希望自己搜索查一下,我这就不费话了;

TCP关于服务器建立的流程设计如下:

1、初始化ServerSocket的端口,阻塞监听;

2、监听到连接后,开辟线程,创建对应通信socket流线程,每一个监听到一个对象对应一个新的线程;

3、socket线程内部阻塞监听接收数据,收到后发送给主界面显示;

4、结束循环,对应关闭socket对象;

5、结束监听,关闭ServerSocket对象(同时要注意关闭还在运行的Socket线程及对象);


关于此部分有一些提醒需要说明:

1、serverSocket最好设置超时,因为最终结束时候,还会被阻塞一次,当然也可以利用api强制结束监听异常;

2、Socket最好设置超时,理由同上;

3、关闭ServerSocket时,记得关闭所有的Socket对象,它们还在运行中;


TCP关于服务器发送消息流程:

1、调用相对应的Socket线程中的Send方法即可,利用PrintWriter实现;


具体实现见代码:

package jason.tcpdemo.coms;

import android.content.Intent;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;

import jason.tcpdemo.funcs.FuncTcpServer;

/**
 * Created by Jason Zhu on 2017-04-24.
 * Email: cloud_happy@163.com
 */

public class TcpServer implements Runnable{
    private String TAG = "TcpServer";
    private int port = 1234;
    private boolean isListen = true;   //线程监听标志位
    public ArrayList<ServerSocketThread> SST = new ArrayList<ServerSocketThread>();
    public TcpServer(int port){
        this.port = port;
    }

    //更改监听标志位
    public void setIsListen(boolean b){
        isListen = b;
    }

    public void closeSelf(){
        isListen = false;
        for (ServerSocketThread s : SST){
            s.isRun = false;
        }
        SST.clear();
    }

    private Socket getSocket(ServerSocket serverSocket){
        try {
            return serverSocket.accept();
        } catch (IOException e) {
            e.printStackTrace();
            Log.i(TAG, "run: 监听超时");
            return null;
        }
    }

    @Override
    public void run() {
        try {
            ServerSocket serverSocket = new ServerSocket(port);
            serverSocket.setSoTimeout(5000);
            while (isListen){
                Log.i(TAG, "run: 开始监听...");

                Socket socket = getSocket(serverSocket);
                if (socket != null){
                    new ServerSocketThread(socket);
                }
            }

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

    public class ServerSocketThread extends Thread{
        Socket socket = null;
        private PrintWriter pw;
        private InputStream is = null;
        private OutputStream os = null;
        private String ip = null;
        private boolean isRun = true;

        ServerSocketThread(Socket socket){
            this.socket = socket;
            ip = socket.getInetAddress().toString();
            Log.i(TAG, "ServerSocketThread:检测到新的客户端联入,ip:" + ip);

            try {
                socket.setSoTimeout(5000);
                os = socket.getOutputStream();
                is = socket.getInputStream();
                pw = new PrintWriter(os,true);
                start();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void send(String msg){
            pw.println(msg);
            pw.flush(); //强制送出数据
        }

        @Override
        public void run() {
            byte buff[]  = new byte[4096];
            String rcvMsg;
            int rcvLen;
            SST.add(this);
            while (isRun && !socket.isClosed() && !socket.isInputShutdown()){
                try {
                    if ((rcvLen = is.read(buff)) != -1 ){
                        rcvMsg = new String(buff,0,rcvLen);
                        Log.i(TAG, "run:收到消息: " + rcvMsg);
                        Intent intent =new Intent();
                        intent.setAction("tcpServerReceiver");
                        intent.putExtra("tcpServerReceiver",rcvMsg);
                        FuncTcpServer.context.sendBroadcast(intent);//将消息发送给主界面
                        if (rcvMsg.equals("QuitServer")){
                            isRun = false;
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            try {
                socket.close();
                SST.clear();
                Log.i(TAG, "run: 断开连接");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

核心代码完成。

主界面代码(几个类和UDP介绍界面代码时是一样的):

package jason.tcpdemo.coms;

import android.content.Intent;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;

import jason.tcpdemo.funcs.FuncTcpServer;

/**
 * Created by Jason Zhu on 2017-04-24.
 * Email: cloud_happy@163.com
 */

public class TcpServer implements Runnable{
    private String TAG = "TcpServer";
    private int port = 1234;
    private boolean isListen = true;   //线程监听标志位
    public ArrayList<ServerSocketThread> SST = new ArrayList<ServerSocketThread>();
    public TcpServer(int port){
        this.port = port;
    }

    //更改监听标志位
    public void setIsListen(boolean b){
        isListen = b;
    }

    public void closeSelf(){
        isListen = false;
        for (ServerSocketThread s : SST){
            s.isRun = false;
        }
        SST.clear();
    }

    private Socket getSocket(ServerSocket serverSocket){
        try {
            return serverSocket.accept();
        } catch (IOException e) {
            e.printStackTrace();
            Log.i(TAG, "run: 监听超时");
            return null;
        }
    }

    @Override
    public void run() {
        try {
            ServerSocket serverSocket = new ServerSocket(port);
            serverSocket.setSoTimeout(5000);
            while (isListen){
                Log.i(TAG, "run: 开始监听...");

                Socket socket = getSocket(serverSocket);
                if (socket != null){
                    new ServerSocketThread(socket);
                }
            }

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

    public class ServerSocketThread extends Thread{
        Socket socket = null;
        private PrintWriter pw;
        private InputStream is = null;
        private OutputStream os = null;
        private String ip = null;
        private boolean isRun = true;

        ServerSocketThread(Socket socket){
            this.socket = socket;
            ip = socket.getInetAddress().toString();
            Log.i(TAG, "ServerSocketThread:检测到新的客户端联入,ip:" + ip);

            try {
                socket.setSoTimeout(5000);
                os = socket.getOutputStream();
                is = socket.getInputStream();
                pw = new PrintWriter(os,true);
                start();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void send(String msg){
            pw.println(msg);
            pw.flush(); //强制送出数据
        }

        @Override
        public void run() {
            byte buff[]  = new byte[4096];
            String rcvMsg;
            int rcvLen;
            SST.add(this);
            while (isRun && !socket.isClosed() && !socket.isInputShutdown()){
                try {
                    if ((rcvLen = is.read(buff)) != -1 ){
                        rcvMsg = new String(buff,0,rcvLen);
                        Log.i(TAG, "run:收到消息: " + rcvMsg);
                        Intent intent =new Intent();
                        intent.setAction("tcpServerReceiver");
                        intent.putExtra("tcpServerReceiver",rcvMsg);
                        FuncTcpServer.context.sendBroadcast(intent);//将消息发送给主界面
                        if (rcvMsg.equals("QuitServer")){
                            isRun = false;
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            try {
                socket.close();
                SST.clear();
                Log.i(TAG, "run: 断开连接");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

再次强调,权限:

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

结束,看效果图:


和写的TCP Client通信效果如下:


开发环境:Android Studio

demo包地址:

TCP(客户端和服务器demo)

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:25737次
    • 积分:426
    • 等级:
    • 排名:千里之外
    • 原创:16篇
    • 转载:0篇
    • 译文:0篇
    • 评论:18条
    最新评论