Android面试题之Java网络通信基础知识

网络通信基础

socket

socket是应用层与TCP/IP协议族通信的中间软件抽象,操作系统把传输层一下的内容都包装了,应用层只需要用socket即可完成网络请求

Tcp是基于流;UDP是基于DatagramPacket数据报;socket可以利用DatagramPacket进行UDP通信

网络请求3部分
  • 连接(客户端和服务端)
  • 读网络数据
  • 写网络数据
BIO、NIO、AIO
  • BIO:阻塞的IO
  • NIO(IO多路复用):一个线程同时管理多个和客户端的连接,一般应用线程数量限制为1024个(系统限制,总共65535,要除去系统使用)
  • AIO(异步IO):目前只有Windows上完全实现

BIO网络编程

服务端
private static ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*2);
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket();
        serverSocket.bind(new InetSocketAddress(10001));
        System.out.println("start server ....");
        try {
            while (true){
                executorService.execute(new ServerTask(serverSocket.accept()));
            }

        }finally {
            serverSocket.close();
        }
    }

    private static class ServerTask implements Runnable{
        private Socket socket;

        public ServerTask(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            //这样会自动关闭流
            try (ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
                 ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());) {
                String input = inputStream.readUTF();
                System.out.println("accept input :" +input);
                outputStream.writeUTF("hello " + input);
                outputStream.flush();

            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if (socket != null) {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
客户端
public static void main(String[] args) throws IOException {
        Socket socket = new Socket();
        InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 10001);
        ObjectOutputStream outputStream = null;
        ObjectInputStream inputStream = null;

        try {
            socket.connect(inetSocketAddress);
            outputStream = new ObjectOutputStream(socket.getOutputStream());
            inputStream = new ObjectInputStream(socket.getInputStream());
            outputStream.writeUTF("hello");
            outputStream.flush();

            System.out.println(inputStream.readUTF());

        } finally {
            if (socket != null) {
                socket.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }

BIO网络编程

Selector、ServerSocketChannel、SocketChannel、Buffer、应用程序

服务端一个线程里面,会有一个Selector,用于接收客户端发来的事件,比如连接、有数产生事件等

ServerSocketChannel:用于处理连接事件,会在Selector里注册OP_ACCEPT事件监听,Selector收到客户端连接事件后会通知ServerSocketChannel;

SocketChannel:用于处理数据读的事件,一个客户端会对应一个SocketChannel;同样它会注册数据读的事件到Selector,有数据发送来了以后,Selector就会通知对应的SocketChannel;

Buffer:用于SocketChannel与服务端应用程序直接的数据操作,有数据时,SocketChannel会写到缓冲区Buffer中,然后应用程序从Buffer中读数据,处理完又写回到Buffer,然后SocketChannel从Buffer中读

有新的客户端连接进来后,会创建新的SocketChannel,进行数据的读写通信

Buffer
Buffer是内存中的一块区域,是一个字节数组,有3个重要变量:Position、limit、capacity;模式的话有读和写2种模式,不能同时进行读和写
  • position:指示当前数据的位置,写模式下,会随着写入数据而移动;当调用flip方法切换到读的模式时,position和limit会发生变化,position会指向0,limit会变成position的值,也就是之前最后写入数据的position
  • capacity:Buffer的容量
Buffer的内存分配:可以在堆上分配,也可以在直接内存上分配
  • 堆上分配:分配速度会快一点,网络通信慢一点,一般业务处理方面多一点

    ByteBuffer buffer = ByteBuffer.allocate(20000);
    
  • 直接内存分配:分配速度会慢一点,网络通信会快一点,一般直接读写网络数据用这个

    ByteBuffer buffer = ByteBuffer.allocateDirect(20000);
    
  • 把byte数组转换为Buffer

    ByteBuffer.wrap(bytes)
    
Buffer的写
  • Channel向Buffer写:用Buffer的read方法,表示从网络读数据写到Buffer
  • 应用程序向Buffer写:用Buffer提供的各种put方法
Buffer的读
  • 从Buffer读数据写到Channel:用Buffer的write方法,表示从Buffer读数据写到channel
  • Buffer从应用程序读:用Buffer的get方法

NIO网络编程

注意点
  • ServerSocketChannel和SocketChannel都要设置为非阻塞,configBolcking(false)
  • selector和ServerSocketChannel初始化的方式都是调用open函数
  • 调用selector.select(1000)表示开启事件监听,每个1秒唤醒一次,但是有事件过来会立刻唤醒处理
  • ServerSocketChannel和SocketChannel通过register函数来向selector注册事件监听
  • register函数可以同时支持多个事件的监听,用位操作符连接:OP_CONNNECT | OP_READ
  • register函数还可以同时注册Buffer,作为第3个参数,这样可以在其他地方,通过SelectionKey的attachment拿到
  • 所有的事件都在SelectionKey里面,包括OP_CONNNECT,OP_READ,OP_WRITE,OP_ACCEPT
  • Buffer在读模式切换到写模式的时候,需要调用flip方法进行模式切换
OP_WRITE和OP_READ事件

我们一般很少使用OP_WRITE事件,因为操作系统在建立socket连接的时候,会为socket创建2个缓冲区(Buffer),一个发送Buffer,一个接收Buffer;当客户端向服务端发送数据的时候,服务端接收缓存接收到数据,就会触发OP_READ事件;这2个缓冲区由操作系统内核管理。

而发送缓存里面只要还有空间可写,哪怕一个字节,就会触发OP_WRITE事件

OP_WRITE使用方式
  • 用SelectionKey的isWritable判断是否有数据
  • Buffer用SelectionKey的attachment来获取
  • 根据Buffer的hasRemaining来判断是否还有数据可写
  • 数据都写完的话要取消写事件的监听,用SelectionKey的interestOps方法
OKhttp中的心跳包

websocket实现,websocket本身定义了跟心跳有关的2个数据帧,实现以后,服务端会自动解析和应答

书籍
  • 《Java网络编程》:网络编程、UDP用socket实现等
  • 《UNIX网络编程》:socket原理等
  • 《Netty实战》:Netty相关的网络开发
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容