ipc之socket的使用(代码片段)

SpidermanL SpidermanL     2022-11-09     577

关键词:

一、概述

  我们知道在开发中,即时通讯、设备间的通信都是使用 Socket 实现,那当然用它来实现进程间通信更是不成问题。Socket 即套接字,是一个对 TCP / IP协议进行封装 的编程调用接口(API) 。通过Socket,我们才能在 Andorid 平台上通过 TCP/IP 协议进行开发。Socket 不是一种协议,而是一个编程调用接口(API),属于传输层(主要解决数据如何在网络中传输)。

  Socket的使用类型主要有两种:

  • 流套接字(streamsocket) :基于 TCP 协议,采用 流的方式 提供可靠的字节流服务
  • 数据报套接字(datagramsocket):基于 UDP 协议,采用 数据报文 提供数据打包发送的服务

  对于 TCP 和 UDP 的讲述,这里就不做说明。

二、Socket 实现 IPC

  IPC 中两个重要角色: 客户端和服务端,示例工程仍旧是两个工程。我们先看服务端如何使用 Socket :

  1. 服务端

  服务端 Service 完整代码:

public class SocketService extends Service 

    private String[] mDefinedMsg = new String[]"你好啊,哈哈", "请问你叫什么名字啊?", "今天北京天气不错啊", "你知道吗,我可以和多个人同时聊天", "给你讲个笑话吧,爱笑的人运气不会太差。";

    int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
    int KEEP_ALIVE_TIME = 1;
    TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
    BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<Runnable>();
    ExecutorService executorService = new ThreadPoolExecutor(NUMBER_OF_CORES, NUMBER_OF_CORES * 2, KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT, taskQueue);

    private boolean isServiceDestroy = false;

    @Override
    public IBinder onBind(Intent intent) 
        return null;
    

    @Override
    public void onCreate() 
        super.onCreate();
        executorService.execute(new TcpServer());
    

    @Override
    public void onDestroy() 
        super.onDestroy();
        isServiceDestroy = true;
    

    private class TcpServer implements Runnable 

        @Override
        public void run() 
            ServerSocket serverSocket = null;
            try 
                //接听本地8688接口
                serverSocket = new ServerSocket(8688);
             catch (IOException e) 
                e.printStackTrace();
            
            while (!isServiceDestroy && serverSocket != null) 
                //接受客户端请求
                try 
                    Socket client = serverSocket.accept();
                    executorService.execute(new TalkWithClient(client));
                 catch (IOException e) 
                    e.printStackTrace();
                
            
        
    

    private class TalkWithClient implements Runnable 

        private Socket socket;

        TalkWithClient(Socket socket) 
            this.socket = socket;
        

        @Override
        public void run() 
            try 
                //用于接收客户端信息
                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                //用于向客户端发送信息
                PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
                out.println("欢迎来到聊天室");
                while (!isServiceDestroy) 
                    String info = in.readLine();
                    if (info == null)  //客户端断开连接
                        break;
                    
                    Log.i("CLIENT_INFO", info);
                    int i = new Random().nextInt(mDefinedMsg.length);
                    String msg = mDefinedMsg[i];
                    out.println(msg);
                    Log.i("Server_INFO", msg);

                
                out.close();
                in.close();
                socket.close();
             catch (IOException e) 
                e.printStackTrace();
            
        
    

  在服务端通过循环的方式轮询是否有客户端接入,并判断服务一旦停止,停止循环。 accpet() 方法在没有客户端接入时,会阻塞当前线程,等到有客户端接入时会继续执行。

 while (!isServiceDestroy && serverSocket != null) 
          //接受客户端请求
          try 
             Socket client = serverSocket.accept();
             executorService.execute(new TalkWithClient(client));
           catch (IOException e) 
          e.printStackTrace();
      
 

  TalkWithClient 是一个 Runnable 实现类,用来与客户端进行交互。通过循环的方式读取客户端传递过来的信息,代码中 readLine() 方法也会阻塞,直到客户端有消息过来继续执行。

while (!isServiceDestroy) 
                    String info = in.readLine();
                    if (info == null)  //客户端断开连接
                        break;
                    
                    Log.i("CLIENT_INFO", info);
                    int i = new Random().nextInt(mDefinedMsg.length);
                    String msg = mDefinedMsg[i];
                    out.println(msg);
                    Log.i("Server_INFO", msg);

                

  2. 客户端

  客户端完整代码:

  

public class MainActivity extends AppCompatActivity 

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

    int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
    int KEEP_ALIVE_TIME = 1;
    TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
    BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<Runnable>();
    ExecutorService executorService = new ThreadPoolExecutor(NUMBER_OF_CORES, NUMBER_OF_CORES * 2, KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT, taskQueue);

    private Socket mClientSocket;
    private PrintWriter mPrintWriter;
    @SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler() 
        @Override
        public void handleMessage(Message msg) 
            switch (msg.what) 
                case MESSAGE_SOCKET_CONNECTED:
                    btnSend.setEnabled(true);
                    break;
                case MESSAGE_RECEIVE_NEW_MSG:
                    msgContainer.setText(String.format("%s%s", msgContainer.getText(), msg.obj));
                    break;
            
        
    ;
    private TextView msgContainer;
    private EditText etMsg;
    private TextView btnSend;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        msgContainer = findViewById(R.id.msg_container);
        etMsg = findViewById(R.id.msg);
        btnSend = findViewById(R.id.btn_send);
        btnSend.setEnabled(false);

        executorService.execute(new Runnable() 
            @Override
            public void run() 
                connectTCPServer();
            
        );
    

    @Override
    protected void onDestroy() 
        if (mClientSocket != null) 
            try 
                mClientSocket.shutdownInput();
                mClientSocket.close();
             catch (IOException e) 
                e.printStackTrace();
            
        
        super.onDestroy();
    

    public void sendMsg(View view) 
        final String msg = etMsg.getText().toString();
        if (!TextUtils.isEmpty(msg) && mPrintWriter != null) 
            executorService.execute(new Runnable() 
                @Override
                public void run() 
                    mPrintWriter.println(msg);
                
            );
            etMsg.setText("");
            String time = formatTimes(System.currentTimeMillis());
            String showMsg = "client" + time + ":" + msg + "\\n";
            msgContainer.setText(String.format("%s%s", msgContainer.getText(), showMsg));
        
    

    private void connectTCPServer() 
        Socket socket = null;
        while (socket == null) 
            try 
                socket = new Socket("localhost", 8688);
                mClientSocket = socket;
                mPrintWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(mClientSocket.getOutputStream())), true);
                mHandler.sendEmptyMessage(MESSAGE_SOCKET_CONNECTED);
             catch (IOException e) 
                SystemClock.sleep(1000);
                //retry
            
        
        //接收服务器消息
        try 
            BufferedReader br = new BufferedReader(new InputStreamReader(mClientSocket.getInputStream()));
            while (!MainActivity.this.isFinishing()) 
                String msg = br.readLine();
                Log.i("CLIENT_RECEIVE", msg);
                if (msg != null) 
                    String time = formatTimes(System.currentTimeMillis());
                    String showMsg = "server" + time + ":" + msg + "\\n";
                    mHandler.obtainMessage(MESSAGE_RECEIVE_NEW_MSG, showMsg).sendToTarget();
                
            
            mPrintWriter.close();
            br.close();
            socket.close();
         catch (IOException e) 
            e.printStackTrace();
        
    

    @SuppressLint("SimpleDateFormat")
    private String formatTimes(long millis) 
        return "(" + new SimpleDateFormat("HH:mm:ss").format(new Date(millis)) + ")";
    

  连接服务端:

  connectTCPServer() 方法是用来连接服务端以及接收服务器消息,接收服务器消息仍然通过循环方式轮询。

  注意:

    Socket 实现 IPC 是网络操作,所以一定记得声明权限:

 

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

 

  最终能够进行传输数据,这里数据可以是任意数据,示例中只是传递了字符串。效果:

      

 

  示例工程代码:

   链接: https://pan.baidu.com/s/1Dq710Z4-vVsrNvgGUky09w 密码: 52fv

 

 

 

网络编程之模块的使用(代码片段)

socket模块的使用1.模仿CS架构模型1.1简版服务器端importsocketserver=socket.socket()#创建一个服务器对象ip_port=(‘192.168.15.79‘,8080)#创建一个元组server.bind(ip_port)#将服务器和ip地址进行绑定server.listen(3)#设置服务器可以同时监听多少个客户... 查看详情

第八讲ipc之信号量(代码片段)

...(InternalProcessCommunication,IPC)  在嵌入式系统中运行的代码主要包括线程和ISR,在他们的运行过程中,他们的运行步骤有时需要同步(按照预定的先后次序运行),他们访问的资源有时需要互斥(一个时刻只允许一个线程访问资... 查看详情

socket编程之使用fsockopen()函数(代码片段)

fsockopen函数:初始化一个套接字连接到指定主机(hostname)get方式:client.php1<?php2//创建连接3$fp=fsockopen(‘localhost‘,80,$error,$errstr,10);45//检测6if(!$fp)7echo$errstr;die;8910//拼接http请求报文11$http=‘‘;1213//请求报文包括3部分请求行请... 查看详情

网络编程之socket&serversocket(代码片段)

网络编程之Socket&ServerSocketSocket:网络套接字,网络插座,建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;socket用... 查看详情

go语言快速入门ipc之socket9

多进程之间的通信常见的手段有管道/信号量/共享内存/Socket等,在上篇文章中介绍了管道的使用方法。管道在多进程通信中使用方便但是也具局限性,当通信双方在不同的机器上的时候通信方式更多采用Socket方式。在这篇文章中... 查看详情

python之socket编程(代码片段)

一、socket简介socket(套接字)是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口,将复杂的TCP/IP协议族隐藏在接口后面,让socket去组织数据以符合指定的协议。 下图左为socket在tcp/ip协议中的角色,右为socket的工作流... 查看详情

网络编程之socket编程(代码片段)

套接字介绍socket介绍Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket... 查看详情

python之socket网络编程(代码片段)

socket解释socekt又称为‘套接字’,用于描述IP和地址端口,是一个通信链路的句柄,应用程序通常通过套接字向网络发出请求或者应答网络请求。socket起源于Unix,所以也遵从“一切皆文件”的基本哲学,对于文件,... 查看详情

go语言快速入门ipc之管道通信8

...,多进程之间的通信主要的手段有管道/信号量/共享内存/Socket等,而管道作为父子进程间进行少量数据传递的有效手段也得到了广泛的应用,在这篇文章中我们来看一下go语言中如何使用管道进行进程进行通信。管道的使用在linu... 查看详情

unixipc之共享内存(代码片段)

...)。这种通信技术往往与其他通信机制(如信号量)结合使用,用于达到进程间的同步及互斥。原理:这种方式是在所有进程的独立空间之外开辟一块内存空间,它不属于任何一个进程,当所有进程都可以访问。利用这样的共享... 查看详情

10.网络编程之socket(代码片段)

目录一、什么是socket?1.1套接字简介1.2套接字地址:主机-端口对二、面向连接的套接字和为无连接的套接字2.1面向连接的套接字2.2无连接的套接字三、python中socket3.1socket()模块函数3.2套接字对象(内置)方法3.3Socket中的一些参数四... 查看详情

androidipc之aidl(代码片段)

...多次被问到跨进程通信,第一次以为人家问的是AIDL的使用于是简明扼要的说了句:了解,但是没有在项目中使用过。后来面试的时候这个问题被提及的频率太高了,于是回来把《Android开发艺术探索》又翻了一遍&#... 查看详情

socket封装之聊天程序

...的计算机(不同的IP+端口)上也能进行通信,就需要用到socket编程。前面说到,要处理多客户端的响应问题,需要I/O复用,即调用select或者epoll。通常我们使用epoll函数,以下例子也是。  接下来,我们需要封装一个地址... 查看详情

进程间通信(ipc)之管道家族(代码片段)

进程间通信:       所谓进程间通信,就是让不同的进程之间可以传播或交换信息,但是不同进程的内存空间是相互独立的(进程的独占性),一般而言是不能相互访问的,所以多个不同进程间要通信&#x... 查看详情

android进阶——framework核心之binder相关预备理论(代码片段)

...信号(Signal)和跟踪(Trace)、插口(Socket)、报文队列(Message)、共享内存(ShareMemory)和信号量(Semaphore)等传统IPC手段 查看详情

android进阶——framework核心之binder相关预备理论(代码片段)

...信号(Signal)和跟踪(Trace)、插口(Socket)、报文队列(Message)、共享内存(ShareMemory)和信号量(Semaphore)等传统IPC手段 查看详情

python之网络编程socket编程(代码片段)

本节内容:Socket语法及相关SocketServer实现多并发    Socket语法及相关 socket概念socket本质上就是在2台网络互通的电脑之间,架设一个通道,两台电脑通过这个通道来实现数据的互相传递。我们知道网络通信都是基... 查看详情

java之socket编程(bio)(代码片段)

效果展示原理分析BIO:即阻塞型IO操作因为我们的代码中有阻塞操作的api-》accept()、read()代码展示packageBIO;importjava.io.FileOutputStream;importjava.io.InputStream;importjava.net.ServerSocket;importjava.net.Socket;importjava.util.A 查看详情