Socket在Java中的使用

这两天研究OkHttp3在Android端的使用,然后想探究其底层通信是怎么实现的。因为原来有个概念就是Android这边的第三方网络框架都是基于HttpClient或者HttpURLConnection来实现的,特别是现在基本上都是使用HttpURLConnection来实现网络通信,所以现在研究OkHttp3的时候,我一直以为其底层也是基于HttpURLConnection来实现网络通信的,及我以为OkHttp3是对HttpURLConnection的封装。但是在研究的过程中发现不是这样的,OkHttp3实际上是基于Socket来进行网络通信的,由于之前对Socket通信一无所知,所以为了进一步的研究OkHttp3,这里来对Socket的使用做一个基本的总结。

Socket是对TCP协议的一种实现,客户端和服务器端各有一个Socket对象,两个Socket对象建立连接后,就可以通过简单的读写操作来实现网络通信,本文就来实现一个Socket客户端和服务器端吧。

1、服务器端代码实现

try {
    // 1、创建一个服务器端Socket,即ServerSocket,指定绑定端口
    ServerSocket serverSocket = new ServerSocket(7779);

    // 2、调用accept方法开始监听,等待客户端连接
    Socket socket = serverSocket.accept();

    // 3、获取输入流,并读取客户端信息
    InputStream is = socket.getInputStream();
    InputStreamReader isr = new InputStreamReader(is);
    BufferedReader br = new BufferedReader(isr);
    String info = br.readLine();
    while (info != null) {
        System.out.println("i am server. message from client is " + info);
        info = br.readLine();
    }
    socket.shutdownInput();//关闭输入流

    // 4、获取输出流,响应客户端请求
    OutputStream os = socket.getOutputStream();
    PrintWriter pw = new PrintWriter(os);
    pw.write("i want say welcome to you");
    pw.flush();//不必等待,立即发送消息

    // 5、关闭资源
    pw.close();
    os.close();
    br.close();
    isr.close();
    is.close();
    socket.close();
    serverSocket.close();
} catch (IOException e) {
    e.printStackTrace();
}

代码中的注释说的很详细,要注意的是accept方法会阻塞线程,直到同客户端建立连接并接收到客户端数据。之后通过socket.getInputStream获取客户端传递过来的消息,并使用BufferedReader对象来读取对象消息。

2、客户端代码实现

try {
    // 1、创建客户端Socket,指定服务器地址以及端口
    Socket socket = new Socket("localhost", 7779);

    // 2、获取输出流,向服务器发送数据
    OutputStream os = socket.getOutputStream();
    PrintWriter pw = new PrintWriter(os);
    pw.write("this is my username and password");
    pw.flush(); //不必等待,立即发送
    socket.shutdownOutput();

    // 3、获取输入流并读取服务器的响应数据
    InputStream is = socket.getInputStream();
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    String info = br.readLine();
    while (info != null) {
        System.out.println("i am client. server says that " + info);
        info = br.readLine();
    }

    // 4、关闭资源
    br.close();
    is.close();
    pw.close();
    socket.close();
} catch (IOException e) {
    e.printStackTrace();
}

客户端和服务器端读写数据方法一直,不过这里是客户端先写后读,而服务器是先读后写。测试时,我碰了一个坑,就是我把客户端放到Android真机上去了,导致socket一直连接不到服务器,刚开始还以为代码有问题,后面把客户端服务器代码都放到电脑上运行,发现效果良好,测试成功。

另外这里要指出一点就是实际上客户端服务器的通信是通过OutputStream来进行的,下面对这点作一些说明。

代码中我们通过pw.write方法来发送数据

pw.write("this is my username and password");

这个方法会调用到PrintWriter.dowrite方法中去

private final void doWrite(char[] buf, int offset, int count) {
    synchronized (lock) {
        if (out != null) {
            try {
                out.write(buf, offset, count);
            } catch (IOException e) {
                setError();
            }
        } else {
            setError();
        }
    }
}

而这里的

out.write(buf, offset, count);

这个代码中的out变量,实际上就是

OutputStream os = socket.getOutputStream();

这里的os变量,现在就明白了一点,我们能够通过socket.getOutputStream返回的OutputStream直接向服务器写数据。

而这里的os对象实际上是PlainSocketOutputStream类的实例,那么os.write的方法实际上是调用到了
PlainSocketOutputStream.write方法中

@Override public void write(int oneByte) throws IOException {
    Streams.writeSingleByte(this, oneByte);
}

这里的Streams是libcore.io.Streams,是比较深层的东西了,这里暂时不深究。

3、参考文献

1、[Java Socket编程----通信是这样炼成的](https://www.cnblogs.com/rocomp/p/4790340.html)

这篇参考文献,讲的关于Socket通信的知识点还蛮多的,感兴趣的童鞋可以去看看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值