Android TCP 协议 Socket 通信

Socket 中文套接字 ,用来描述 IP 地址和端口好,是通讯链的句柄,应用程序可以通过 Socket 向网络发送请求或者应答请求

Socket 是支持 TCP/IP 协议的网络通讯的基本操作单元,是对网络通讯过程中端点的抽象表示,包含了进行通讯所必须的五个基本信息:连接网络使用的协议,本地主机的 IP 地址,本地进程的端口号,远程主机的 IP 地址和远程主机上进程的端口号

Socket 通信模型

  1. 创建 ServerSocketSocket

  2. 打开连接到的 Socket 的输入/输出流

  3. 按照协议对 Socket 进行读/写操作

  4. 关闭输入输出流,以及 Socket

我们接下来写一个简单的例子,开启服务端后,客户端点击按钮然后链接服务端, 并向服务端发送一串字符串,表示通过 Socket 链接上服务器

Socket 服务端

服务器端创建一个网络监听的流程如下

  1. 创建 ServerSocket 对象,绑定监听的端口

  2. 调用 accept() 方法监听客户端的请求

  3. 连接建立后,通过输入流读取客户端发送的请求信息

  4. 通过输出流向客户端发送响应信息

  5. 关闭相关资源

范例

在某个目录下创建 TcpServer.java,比如 d:\dev

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Enumeration;

public class TcpServer {

    public static String getServAddr() {

        try {
            Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
            while (allNetInterfaces.hasMoreElements()) {
                NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();

                // 去除回环接口,子接口,未运行和接口
                if (netInterface.isLoopback() || netInterface.isVirtual() || !netInterface.isUp()) {
                    continue;
                }

                Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress ip = addresses.nextElement();
                    if (ip != null) {
                        // ipv4
                        if (ip instanceof Inet4Address) {
                            if (ip.getHostAddress().startsWith("192") || ip.getHostAddress().startsWith("10")
                                    || ip.getHostAddress().startsWith("172") || ip.getHostAddress().startsWith("169")) {
                                return ip.getHostAddress();
                            }
                        }
                    }
                }
            }
        } catch (SocketException e) {
            System.err.println("Error when getting host ip address"+ e.getMessage());
        }

        return "";
    }

    public static void main(String[] args) throws IOException {

        //1.创建一个服务器端 Socket,即 ServerSocket 指定绑定的端口,并监听此端口

        ServerSocket serverSocket = new ServerSocket(12345);

        System.out.println("服务器已经运行在" + getServAddr() + ":12345 ,等待客户端发送数据");

        while ( true ) {

            //2.调用accept()等待客户端连接
            Socket socket = serverSocket.accept();

            //3.连接后获取输入流,读取客户端信息
            InputStream is=null;
            InputStreamReader isr=null;
            BufferedReader br=null;
            OutputStream os=null;
            PrintWriter pw=null;
            is = socket.getInputStream();     //获取输入流
            isr = new InputStreamReader(is,"UTF-8");
            br = new BufferedReader(isr);
            String info = null;
            while((info=br.readLine())!=null){//循环读取客户端的信息
                System.out.println("客户端发送过来的信息" + info);
            }
            socket.shutdownInput();//关闭输入流
        }
    }
}

打开终端或命令行提示符,输入以下命令运行 TcpServer.java

javac TcpServer.java && java TcpServer

如果出现下面的文字则说明服务正常启动

服务器已经运行在 192.168.0.108:12345 ,等待客户端发送数据

你的 ip 可能不同

然后客户端就可以通过 192.168.0.108:12345 访问我们的 UDP Server 了

Socket 客户端

Android APP 端创建一个链接到网络服务器的套接字的流程如下

  1. 创建 Socket 对象,指明需要链接的服务器的地址和端号

  2. 链接建立后,通过输出流向服务器发送请求信息

  3. 通过输出流获取服务器响应的信息

  4. 关闭相关资源

范例

  1. 创建一个 空的 Android 项目 cn.twle.android.TcpSocket

  2. 修改 AndroidManifest.xml 添加网络权限

    <uses-permission android:name="android.permission.INTERNET"/>
    
  3. 修改 activity_main.xml 添加一个 TextView 用来显示信息

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="16dp"
        android:orientation="vertical">
    
        <TextView
            android:id="@+id/ms_msg"
            android:layout_height="match_parent"
            android:layout_width="match_parent"
            android:text="" />
    
    </LinearLayout>
    
  4. 修改 MainActivity.java

    package cn.twle.android.tcpsocket;
    
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.support.v7.app.AppCompatActivity;
    import android.widget.TextView;
    
    import java.io.OutputStream;
    import java.io.PrintWriter;
    import java.net.InetAddress;
    import java.net.Socket;
    
    public class MainActivity extends AppCompatActivity {
    
        private  TextView ms_msg;
        private  StringBuilder sb;
    
        private Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch ( msg.what) {
                    case 0x1001:
                        ms_msg.setText(sb.toString());
                        break;
                }
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            TextView ms_msg = (TextView) findViewById(R.id.ms_msg);
    
            new Thread(new Runnable(){
    
                @Override
                public void run(){
                    try {
                        //1.创建客户端Socket,指定服务器地址和端口
                        Socket socket = new Socket("192.168.0.108", 12345);
                        //2.获取输出流,向服务器端发送信息
                        OutputStream os = socket.getOutputStream();//字节输出流
                        PrintWriter pw = new PrintWriter(os);//将输出流包装为打印流
                        //获取客户端的IP地址
                        InetAddress address = InetAddress.getLocalHost();
                        String ip = address.getHostAddress();
                        pw.write(">>> 客户端:~" + ip + "~ 接入服务器!!");
                        pw.flush();
                        socket.shutdownOutput();//关闭输出流
                        socket.close();
                    } catch (Exception e ) {
                        e.printStackTrace();
                    }
                }
            }).start();
    
        }
    }
    

因为 Android 不允许在主线程 (UI线程) 中做网络操作,需要我们自己另开一个线程来连接 Socket

运行之后我们的 APP 输出如下

再看一下服务器端,输出

服务器已经运行在192.168.0.108:12345 ,等待客户端发送数据
客户端发送过来的信息>>> 客户端:~127.0.0.1~ 接入服务器!!

说明服务器端已经接收到了数据

Android 基础教程

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.