Socket,你须要知道的事儿

what is socket

socket做为一种抽象层,应用程序经过它来发送和接收数据,使用socket能够将应用程序与处于同一网络中的其余应用程序进行通讯交互。简而言之,socket提供了应用程序内部与外界通讯的端口以及为通讯双方提供了数据传输的通道。javascript

对比

android与服务器通讯主要有两种方式:Http通讯与Socket通讯。java

差别:android

Http通讯git

  • 请求—响应方式”
  • 请求时创建链接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据

Socket通讯github

  • 双方创建起链接后就能够直接进行数据的传输,在链接时可实现信息的主动推送,而不须要每次由客户端想服务器发送请求
  • 数据丢失率低,使用简单,易于移植

模型

Socket基本通讯模式以下:服务器

从上面模型能够看出Socket能够是基于Tcp协议的Socket通讯或基于Udp协议的Socket通讯,今天笔者就讲基于Tcp的Socket通讯。网络

Tcp通讯模型以下:app

了解模型后,优先须要理解Tcp Socket原理,重点来啦~socket

原理

服务器端首先声明一个ServerSocket对象而且指定端口号,而后调用Serversocket的accept()方法接收客户端的数据。accept()方法在没有数据进行接收的处于堵塞状态。(Socketsocket=serversocket.accept()),一旦接收到数据,经过inputstream读取接收的数据。 客户端建立一个Socket对象,指定服务器端的ip地址和端口号(Socket socket=new Socket("172.17.30.12",9999);),经过inputstream读取数据,获取服务器发出的数据(OutputStream outputstream = socket.getOutputStream()),最后将要发送的数据写入到outputstream便可进行TCP协议的socket数据传输。tcp

实践

原理懂了,则需实践,毛主席说过“实践是检验真理的惟一标准”。 代码走起来~~~

客户端:

package cn.jianke.socket.tcp;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;

/** * @className: TcpSocketClient * @classDescription: tcp套接字客户端 * @author: leibing * @createTime: 2016/10/06 */
public class TcpSocketClient {
    // 服务端地址
    private String serverIp = "172.17.30.12";
    // 服务端端口号
    private int serverPort = 9999;
    // 套接字
    private Socket mSocket = null;
    // 缓冲区读取
    private BufferedReader in = null;
    // 字符打印流
    private PrintWriter out = null;
    // tcp套接字监听
    private TcpSocketListener mTcpSocketListener;
    // 内容
    private String content = "";

    /** * 构造函数 * @author leibing * @createTime 2016/10/06 * @lastModify 2016/10/06 * @param mTcpSocketListener tcp套接字监听 * @return */
    public TcpSocketClient(TcpSocketListener mTcpSocketListener){
        this.mTcpSocketListener = mTcpSocketListener;
    }

    /** * 构造函数 * @author leibing * @createTime 2016/10/06 * @lastModify 2016/10/06 * @param serverIp = 服务端地址 * @param serverPort 服务端口号 * @param mTcpSocketListener tcp套接字监听 * @return */
    public TcpSocketClient(String serverIp, int serverPort , TcpSocketListener mTcpSocketListener){
        this.serverIp  = serverIp;
        this.serverPort = serverPort;
        this.mTcpSocketListener = mTcpSocketListener;
    }

    /** * 启动tcp套接字链接 * @author leibing * @createTime 2016/10/06 * @lastModify 2016/10/06 * @param * @return */
    public void startTcpSocketConnect(){
        // 开启一个线程启动tcp socket
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    mSocket = new Socket(serverIp, serverPort);
                    in = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
                    out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
                            mSocket.getOutputStream())), true);
                    while (true) {
                        if (mSocket.isConnected()) {
                            if (!mSocket.isInputShutdown()) {
                                if ((content = in.readLine()) != null) {
                                    content += "\n";
                                    if (mTcpSocketListener != null)
                                        mTcpSocketListener.callBackContent(content);
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /** * 经过tcp套接字发送消息 * @author leibing * @createTime 2016/10/06 * @lastModify 2016/10/06 * @param * @return */
    public void sendMessageByTcpSocket(String msg){
        if (mSocket != null && mSocket.isConnected()){
            if (!mSocket.isOutputShutdown() && out != null){
                out.println(msg);
                if (mTcpSocketListener != null)
                    mTcpSocketListener.clearInputContent();
            }
        }
    }

    /** * @interfaceName: * @interfaceDescription: tcp套接字监听 * @author: leibing * @createTime: 2016/10/06 */
    public interface TcpSocketListener{
        // 回调内容
        void callBackContent(String content);
        // 清除输入框内容
        void clearInputContent();
    }
}复制代码

封装一个TcpSocket客户端类,写构造函数,设置服务端ip地址、端口号并设置监听(用于回调从Socket服务端接收的数据),写启动tcp套接字链接方法,其中BufferedReader in用于接收服务端数据,PrintWriter out用于向服务端发送数据。

package cn.jianke.socket.module;

import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import cn.jianke.socket.R;
import cn.jianke.socket.tcp.TcpSocketClient;

/** * @className:MainActivity * @classDescription: tcp套接字客户端页面 * @author: leibing * @createTime: 2016/10/06 */
public class MainActivity extends AppCompatActivity {
    // 服务端地址
    private final static String serverIp = "172.17.30.12";
    // 服务端口号
    private final static int serverPort = 9999;
    // 控件
    private TextView showTv;
    private EditText contentEdt;
    private Button sendBtn;
    // tcp套接字客户端
    private TcpSocketClient mTcpSocketClient;
    // 自定义Handler,用于更新Ui
    private Handler mHandler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // findView
        showTv = (TextView) findViewById(R.id.tv_show);
        contentEdt = (EditText) findViewById(R.id.edt_content);
        // 初始化tcp套接字客户端
        mTcpSocketClient = new TcpSocketClient(serverIp, serverPort,
                new TcpSocketClient.TcpSocketListener() {
            @Override
            public void callBackContent(final String content) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if (showTv != null)
                            showTv.setText(showTv.getText().toString() + content);
                    }
                });
            }

                    @Override
                    public void clearInputContent() {
                        if (contentEdt != null)
                            contentEdt.setText("");
                    }
                });
        // 启动tcp套接字链接
        mTcpSocketClient.startTcpSocketConnect();
        // onClick
        findViewById(R.id.btn_send).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String msg = contentEdt.getText().toString().trim();
                mTcpSocketClient.sendMessageByTcpSocket(msg);
            }
        });
    }

    @Override
    protected void onDestroy() {
        // 断开tcp连接
        if (mTcpSocketClient != null)
            mTcpSocketClient.sendMessageByTcpSocket("exit");
        super.onDestroy();
    }
}复制代码

在页面初始TcpSocketClient类(设置服务端ip地址、端口以及设置监听),并启动启动tcp套接字链接。

服务端:

package cn.jianke.socket.tcp;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/** * @className: TcpSocketServer * @classDescription: tcp套接字服务端 * @author: leibing * @createTime: 2016/10/06 */
public class TcpSocketServer {
    // 端口号
    private final static int serverPort = 9999;
    // tcp套接字列表
    private List<Socket> mList = new ArrayList<Socket>();
    // 套接字服务
    private ServerSocket server = null;
    // 线程池
    private ExecutorService mExecutorService = null;

    /** * 主函数入口 * @author leibing * @createTime 2016/10/06 * @lastModify 2016/10/06 * @param args * @return */
    public static void main(String[] args) {
        // 启动tcp套接字服务
        new TcpSocketServer();
    }

    /** * 启动tcp套接字服务 * @author leibing * @createTime 2016/10/06 * @lastModify 2016/10/06 * @param * @return */
    public TcpSocketServer() {
        try {
            server = new ServerSocket(serverPort);
            System.out.print("server start ...");
            Socket client = null;
            //create a thread pool
            mExecutorService = Executors.newCachedThreadPool();
            while(true) {
                client = server.accept();
                mList.add(client);
                //start a new thread to handle the connection
                mExecutorService.execute(new TcpSocketService(client));
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    /** * @className: TcpSocketService * @classDescription: tcp套接字服务 * @author: leibing * @createTime: 2016/10/06 */
    class TcpSocketService implements Runnable {
            // 套接字
            private Socket socket;
            // 缓冲区读取
            private BufferedReader in = null;
            // 消息
            private String msg = "";

            /** * 构造函数 * @author leibing * @createTime 2016/10/06 * @lastModify 2016/10/06 * @param socket 套接字 * @return */
            public TcpSocketService(Socket socket) {
                this.socket = socket;
                try {
                    in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    msg = "tips: user" +this.socket.getInetAddress() + " come";  
                    this.sendmsg();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }

            @Override
            public void run() {
                // TODO Auto-generated method stub
                try {
                    while(true) {
                        if((msg = in.readLine())!= null) {
                            if(msg.equals("exit")) {
                                mList.remove(socket);
                                in.close();
                                msg = "tips: user" +this.socket.getInetAddress() + " exit";
                                socket.close();
                                this.sendmsg();
                                break;
                            } else {
                                msg = socket.getInetAddress() + ":" + msg;
                                this.sendmsg();
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        /** * 发送消息 * @author leibing * @createTime 2016/10/06 * @lastModify 2016/10/06 * @param * @return */
        public void sendmsg() {
               System.out.println(msg);
               int num =mList.size();
               for (int index = 0; index < num; index ++) {
                   Socket mSocket = mList.get(index);
                   PrintWriter pout = null;
                   try {
                       pout = new PrintWriter(new BufferedWriter(
                               new OutputStreamWriter(mSocket.getOutputStream())),true);
                       pout.println(msg);
                   }catch (IOException e) {
                       e.printStackTrace();
                   }
               }
           }
        }    
}复制代码

初始化ServerSocket指定端口,将tcp套接字服务放入线程池与客户端进行交互,BufferedReader in用于接收客户端发来的数据,PrintWriter pout 用于向客户端发送数据。

效果图

服务端:

server start ...tips: user/172.17.30.15 come
/172.17.30.15:够么
/172.17.30.15:不够
/172.17.30.15:哈根
/172.17.30.15:里咯哦图
/172.17.30.15:诺魔图
/172.17.30.15:这是一个socket
/172.17.30.15:hgdh复制代码

客户端:

Demo地址:Socket

关于做者

相关文章
相关标签/搜索