关于Scoket的一些愚见

这是接着上一章,关于Socket以及输入输出流的知识点。

Socket在Java网络编程中十分常见,而在Android则是使用封装好的HttpClient和HttpURLConnection。
不过,随着版本的推移,HttpClient逐渐被费用,而HttpURLConnection逐渐的完善。

不过这些都是题外话,我现在要总结的东西是Socket,相比上面两者Socket我用到的机会不多,现在慢慢的总结一遍。

Socket中文名为套字节。下面究竟是怎么要一个协议暂时不需要知道,我们知道这是基于C/S通信模型实现的,需要一个服务端,客户端。客户端需要知道服务端的地址,这要再通过IO进行传输就能完成一次交互。

同样的这个思想可以套用到进程间通信,只是我们要设置并非IP地址+端口。而是本地由操作系统分配下来的端口就OK。

一般来说,通信的模型就像下面:
socket通信

下面是一个Socket实现的,自己能够对应自己的客户端发送,服务端就能随机回答一句话,也就是说少一个客户端,只有服务器和一个客户端相互交流:

Service端:

public class TPCService extends Service{
    //判断Service是否被销毁
    private boolean mIsServiceDestroy = false;
    private String[] mDefinedMessage = new String[]{
            "你好呀,Hello!",
            "请问你叫啥呀",
            "今天北京天气不错啊",
            "你知道吗?我可是可以和很多人一起聊天的呀"
    };

    private class TcpService implements Runnable{

        @Override
        public void run() {
            // TODO Auto-generated method stub
            ServerSocket serverSocket = null;
            try{
                //约定的端口
                serverSocket = new ServerSocket(8688);
            }catch (IOException e) {
                // TODO: handle exception
                System.err.println("establish tcp server failed,port:8688");
                e.printStackTrace();
                return;
            }

            while (!mIsServiceDestroy) {
                try {
                    //阻塞等待客户端的连接
                    final Socket client = serverSocket.accept();
                    System.out.print("accept");
                    new Thread(){
                        @Override
                        public void run(){
                            try {
                                responseClient(client);
                            } catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        }
                    }.start();
                } catch (IOException e) {
                    // TODO: handle exception
                    e.printStackTrace();
                }
            }
        }

    }

    private void responseClient(Socket socket)throws IOException{
        //客户端输入的流
        BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        //从服务端输出到客户端的流
        PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true) ;
        //一进聊天首先输出文字
        out.println("欢迎来到聊天室");
        while(!mIsServiceDestroy){
            //读输入流
            String str = in.readLine();
            System.out.println("msg from client:"+str);
            if(str == null){
                break;
            }

            int i = new Random().nextInt(mDefinedMessage.length);
            String msg = mDefinedMessage[i];
            System.out.println("Send:"+msg);
            //将信息写入输出流
            out.println(msg);

        }
        System.out.println("client quit");
        out.close();
        in.close(); 
        socket.close();
    }

    @Override
    public void onCreate(){
        //Service还是在主线程中工作,因此网络连接这种耗时工作将要在子线程中完成
        new Thread(new TcpService()).start();
        super.onCreate();
    }

    @Override
    public void onDestroy(){
        mIsServiceDestroy = true;
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }


}

客户端:

public class MainActivity extends Activity implements OnClickListener{

    private static final int MESSAGE_RECEIVE_NEW_MSG = 1;
    private static final int MESSAGE_SOCKET_CONNECTD = 2;

    private Button button;
    private EditText edit;
    private TextView text;

    private PrintWriter writer;
    private Socket client;

    //UI中修改组件,最好交给Handler去完成
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg){
            switch (msg.what) {
            case MESSAGE_RECEIVE_NEW_MSG:
                text.setText(text.getText()+(String)msg.obj);
                break;

            case MESSAGE_SOCKET_CONNECTD:
                button.setEnabled(true);
                break;

            default:
                break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        edit = (EditText)findViewById(R.id.msg);
        text = (TextView)findViewById(R.id.msg_container);
        button = (Button)findViewById(R.id.send);
        button.setOnClickListener(this);
        Intent intent = new Intent(MainActivity.this,TPCService.class);
        startService(intent);
        //连接网络的线程
        new Thread(){
            @Override
            public void run(){
                connectTPCService();
            }
        }.start();
    }

    @Override
    protected void onDestroy(){
        if(client != null){
            try {
                client.shutdownInput();
                client.close();
            } catch (IOException e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }
        super.onDestroy();
    }



    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        if(v == button){
            final String msg = edit.getText().toString();
            if(!TextUtils.isEmpty(msg) && writer != null){
                writer.println(msg);
                Log.e("tag","client send:"+msg);
                edit.setText("");
                String time = formatDateTime(System.currentTimeMillis());
                final String showedMsg = "self" + time + ":" + msg + "\n";
                text.setText(text.getText()+ showedMsg);
            }
        }

    }
    //获取实现的格式
    private String formatDateTime(long time){
        return new SimpleDateFormat("(HH:mm:ss)").format(new Date(time));
    }

    private void connectTPCService(){
        Socket socket = null;
        //socket为空的时候,每个1秒不断的尝试的连接
        while (socket == null) {
            try {
                //要连接的端口
                socket = new Socket("localhost",8688);
                client = socket;
                writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
                mHandler.sendEmptyMessage(MESSAGE_SOCKET_CONNECTD);
            } catch (UnknownHostException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                SystemClock.sleep(1000);
                System.out.println("retry connected");
                e.printStackTrace();
            }
        }

        //读取从服务端传入的流
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            while (!MainActivity.this.isFinishing()) {
                String msg = br.readLine();
//              System.out.println("receive:"+msg);
                if(msg != null){
                    String time = formatDateTime(System.currentTimeMillis());
                    final String showedMsg = "server" + time + ":"+msg+"\n";
                    mHandler.obtainMessage(MESSAGE_RECEIVE_NEW_MSG, showedMsg).sendToTarget();
                }
            }
            System.out.println("quit..");
            writer.close();
            br.close();
            socket.close();
        } catch (IOException e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }




}

注意,打开了socket接口,不用了记住一定要将其关闭。就像IO接口一样,这是十分消耗资源的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值