• 从零开始学android -- 简易的socket通信


    先来介绍下socket,网上摘抄点资料,免得自己打字了

    网络中进程之间如何通信?

         本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类:

    • 1、消息传递(管道、FIFO、消息队列)
    • 2、同步(互斥量、条件变量、读写锁、文件和写记录锁、信号量)
    • 3、共享内存(匿名的和具名的)
    • 4、远程过程调用(Solaris门和Sun RPC)

         但这些都不是本文的主题!我们要讨论的是网络中进程之间如何通信?首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的。其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。

    使用TCP/IP协议的应用程序通常采用应用编程接口:UNIX  BSD的套接字(socket)和UNIX System V的TLI(已经被淘汰),来实现网络进程之间的通信。就目前而言,几乎所有的应用程序都是采用socket,而现在又是网络时代,网络中进程通信是无处不在,这就是我为什么说“一切皆socket”。

    2、什么是Socket?

          上面我们已经知道网络中的进程是通过socket来通信的,那什么是socket呢?socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。我的理解就是Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。

         socket一词的起源:在组网领域的首次使用是在1970年2月12日发布的文献IETF RFC33中发现的,撰写者为Stephen Carr、Steve Crocker和Vint Cerf。根据美国计算机历史博物馆的记载,Croker写道:“命名空间的元素都可称为套接字接口。一个套接字接口构成一个连接的一端,而一个连接可完全由一对套接字接口规定。”计算机历史博物馆补充道:“这比BSD的套接字接口定义早了大约12年。”

    TCP/IP协议基础

      Ip协议是internet上使用的一个关键协议,它的全称是Intentnet Protocol ,即Internet协议,通常简称IP协议。通过IP协议,使Internet成为一个允许连接不同类型的计算机和不同操作系统的网络。

      要使两台计算机彼此之间进行通信,必须使两台计算机使用一种“语言” ,IP协议只保证计算机能发送和接收分组数据。IP协议负责将消息从一个主机传送到另一个主机,消息在传送的过程中被分割成一个个小包。

    尽管计算机通过安装IP软件,保证了计算机之间可以发送和接收数据,但IP协议还不能解决数据分组在传输过程中可能出现的问题。因此,若要解决可能出现的问题,连接上Internet的计算机还需要安装TCP协议来提供可靠并且无差错的通信服务。

      TCP协议被称为一种端对端协议。这是因为它为两台计算机之间的连接起了重要作用:当一台计算机需要与另一台远程计算机连接时,TCP协议会让他们建立一个连接:用于发送和接收数据的虚拟链路。

    TCP协议负责收集这些信息包。并将其按照适当的次序放好传送,在接收端收到后再将其正确的还原。TCP协议保证了数据包在传送中准确无误。TCP协议使用重发机制:当一个通信实体发送一个消息给另一个通信实体后,需要收到另一个通信实体的确认消息,如果没有收到另一个通信实体的确认消息,则会再次重发刚才发送的消息。

      通过这种重发机制。TCP协议向应用程序提供可靠的通信连接,使他能够自动适应网上的各种变化。即使在Internet暂时出现堵塞的情况下,TCP也能保证通信的可靠。

      综上所述,虽然IP和TCP协议的功能不同,也可以分开单独使用,但它们是在同一时期作为一个协议来设计的,并且在功能上也是互补的。只有两者结合,才能保证Internet在复杂的环境下正常运行。凡是要连接Internet的计算机,都必须同时安装和使用这两个协议,因此在实际中常把这两个协议统称为TCP/IP协议。

    使用ServerSocket创建TCP服务端

      上图中我们可以看出Tcp通信的两个通信实体是没有区分服务端和客户端的,但是实在他们建立起连接后的状态。如果没有建立起连接的话,必须需要有一端释放出“主动”的姿态,等待连接,那么这一端就是服务端,连接的一端就是客户端。

    先来看看效果:

      服务端:pc上

      客户端:真机和模拟器

      目的:建立一个多客户端的简易聊天室。(下图你也能看到,模拟器连接上了,pc服务端会打印一个连接数1,真机连接上服务端了,pc端会打印一个连接数2)

    PC服务端代码编写:

    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.InetAddress;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.ArrayList;
    
    public class MyServer {
    
        
        public static ArrayList<Socket> socketList = new ArrayList<>();
        
        public static void main(String[] args) {
            
            try {
                //建立服务端
                InetAddress inetAddress = InetAddress.getLocalHost();
                //打印本地的ip
                System.out.println("ip:"+inetAddress.getHostAddress());
                ServerSocket serverSocket = new ServerSocket(30000);
                while(true){
                    //循环接收socket
                    Socket socket = serverSocket.accept();
                    
                    OutputStream os = socket.getOutputStream();
                    os.write(("欢迎连接Mdm服务端socket...
    ").getBytes("utf-8"));
    //                os.close();
                    socketList.add(socket); //join in socketList
                    new Thread(new ServerThread(socket)).start(); //new thread Deal with this matter. 
                    
                    System.out.println("当前连接数"+socketList.size());
                }
                
                //that end java code written.
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        
    }

    ServerThread.java

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.UnsupportedEncodingException;
    import java.net.Socket;
    
    public class ServerThread implements Runnable {
    
        BufferedReader br = null;
        
        Socket s;
        
        public ServerThread(Socket s){
            
            try {
                this.s = s;
                br = new BufferedReader(new InputStreamReader(s.getInputStream(),"utf-8"));
                
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        @Override
        public void run() {
            
            String content = null;
            //循环判断client发送过来的数据不为null
            while((content = readFromClient()) != null){
                
                //遍历每一列表中的每一个socket给他们发送消息类似聊天室的感觉每个人都收到了消息
                for (Socket otherClient : MyServer.socketList) {
                    
                    try {
                        //输出流进行输出
                        OutputStream os = otherClient.getOutputStream();
                        os.write((content+"
    ").getBytes("utf-8"));
    //                    os.close();//关闭流
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                
            }
        }
        
        /**
         * 获取从clientSocket中发过来的消息
         * @return
         */
        private String readFromClient(){
            
            try {
                return br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
                //if hava excption  remove this socket in socketList.
                MyServer.socketList.remove(s);
            }
            return null;
        }
    }

    Android 客户端代码

    activity_multi_thread_client.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
    
            <!--用来发送给服务端的数据-->
            <EditText
                android:id="@+id/input"
                android:layout_weight="1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
    
            <Button
                android:id="@+id/send"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="send"
                />
        </LinearLayout>
    
    
        <!--用来获取显示服务端发送过来的数据-->
        <TextView
            android:id="@+id/show"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="top"
            android:background="#ffff"
            android:textSize="14dp"/>
    
    </LinearLayout>
    MultiThreadClient.java

    public class MultiThreadClient extends AppCompatActivity {
    
    
        private EditText input;
        private TextView show;
    
        private Handler handler;
    
        private ClientThread clientThread;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_multi_thread_client);
    
            input = (EditText) findViewById(R.id.input);
            show = (TextView) findViewById(R.id.show);
    
            handler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    //receive ServerSocket data.
                    if(msg.what == 0x123)
                    show.append("
    "+msg.obj.toString());
                }
            };
            clientThread = new ClientThread(handler);
            new Thread(clientThread).start();
    
            Button send = (Button) findViewById(R.id.send);
            send.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    Message msg = Message.obtain();
                    msg.what = 0x345;
                    msg.obj = input.getText().toString();
                    clientThread.sendHandler.sendMessage(msg);
                    input.setText("");
                }
            });
    
        }
    }

    ClientThread.java

    public class ClientThread implements Runnable {
    
        //接收服务端发送的数据
        private Handler handler;
    
        //send client data.
        public Handler sendHandler;
    
        private BufferedReader br;
        private OutputStream os;
    
    
        public ClientThread(Handler handler){
            this.handler = handler;
        }
        @Override
        public void run() {
            try {
                //connection server Socket
                Socket socket = new Socket("192.168.1.110",30000);
                br = new BufferedReader(new InputStreamReader(socket.getInputStream(),"utf-8"));
                os = socket.getOutputStream();
    
                //print server data in TextView
                new Thread(){
                    @Override
                    public void run() {
                        try {
                            String content = null;
                            while ((content = br.readLine()) != null) {
                                Message msg = Message.obtain();
                                msg.what = 0x123;
                                msg.obj = content;
                                handler.sendMessage(msg);
                            }
                        }catch (IOException ex){
                            ex.printStackTrace();
                        }
                    }
                }.start();
    
                //send client data to server
                Looper.prepare();
                sendHandler = new Handler(){
                    @Override
                    public void handleMessage(Message msg) {
                        try {
                            if(msg.what == 0x345) {
                                os.write((msg.obj.toString()+"
    ").getBytes("utf-8")); //这地方后面一定得加上
    因为服务端那边readLine()读取的是以换行为结束标识。之前发不出去数据,代码调试了好久,头都大了。
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                };
                Looper.loop();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    }

    ok。

  • 相关阅读:
    两线段是否相交模板
    树的距离
    Codeforces Round #369 (Div. 2)-D Directed Roads
    Codeforces Round #369 (Div. 2)-C Coloring Trees
    Codeforces Round #374 (Div. 2)-D Maxim and Array
    zstu-4243 牛吃草
    Codeforces Round #447 (Div. 2)
    zstu 4247-萌新的旅行
    CDQ分治求前缀和
    self.faceshowing = !self.facshowing无效,了,原来set
  • 原文地址:https://www.cnblogs.com/woaixingxing/p/7603057.html
Copyright © 2020-2023  润新知