网络通信学习笔记(三)---TCP通信及文件上传

简介: 网络通信学习笔记(三)---TCP通信及文件上传

1. TCP协议


1.1. TCP通信

因为我们上面说过,TCP是明确区分客户端与服务端的,所以我们编写代码的过程中必须要编写两个类分别代表客户端与服务端.

我们先编写客户端的代码:


public static void main(String[] args) throws IOException {
        Socket socket=null;
        OutputStream os=null;
        try {
            //首先先创建一个InetAddress对象,表明我们客户端过会是要和哪台服务器进行连接
            InetAddress serverIP=InetAddress.getByName("127.0.0.1");
            int port=9999;
            //之后我们创建一个连接连接到该服务器上
            socket=new Socket(serverIP,port);
            //因为我们是客户端所以我们需要给服务器发消息,所以我们再创建一个文件流,帮助我们写入数据
            os=socket.getOutputStream();
            //之后就是通过文件流来写入数据
            os.write("hi,you are here too".getBytes());
        }
        catch (IOException e){
            e.printStackTrace();
        }
    //这里最好就是关闭好连接,否则可能会出现下面的错误
    finally {
            os.close();
            socket.close();
        }
    }

服务端代码:

public static void main(String[] args) throws IOException {
        ServerSocket serverSocket=null;
        Socket socket=null;
        InputStream is=null;
        ByteArrayOutputStream baos=null;
        try {
            //创建客户端需要连接的服务端
            serverSocket=new ServerSocket(9999);
            while (true){
                //等待客户端连接过来
                socket=serverSocket.accept();
                //读取客户端的消息
                is=socket.getInputStream();
                baos=new ByteArrayOutputStream();
                byte[] buffer=new byte[1024];
                int len;
//            do {
//                len=is.read(buffer);
//                baos.write(buffer,0,len);
//            } while (is.available() != 0);
                while ((len=is.read(buffer))!=-1){
                    baos.write(buffer,0,len);
                }
                System.out.println(baos.toString());
            }
        }
        catch (IOException e){
            e.printStackTrace();
        }
        //这里最好就是关闭好连接,否则可能会出现下面的错误
        finally {
            baos.close();
            is.close();
            socket.close();
            serverSocket.close();
        }
    }

20200917113406219.png


所以最好还是将整个连接关闭好,否则可能会出现上述错误;

这种错误主要就是下面这个原因:

客户端发送完数据之后,并没有关闭socket连接,那么服务端在读取缓冲区的数据是就有可能会出现这样的错误,主要就是 读写操作出现冲突

效果如下:

image.gif


1.2. TCP文件上传


其实本质上这里和我们上面写的TCP通信其实是差不多的,只不过这里因为我们需要上传的是文件所以我们必须使用文件专属的流,所以需要使用 FileInputStream 与 FileOutputStream ,还有一个就是 关闭连接方面 ,这个关闭连接和上面的关闭连接不太一样,具体我们在下面的代码中具体讲.


其他的操作本质上就是一致的.


客户端:

 public static void main(String[] args) throws IOException {
        //创建一个Socket连接
        Socket socket=new Socket(InetAddress.getByName("127.0.0.1"),9000);
    //读取一个输出流
        OutputStream os=socket.getOutputStream();
    //读取文件
        FileInputStream fis=new FileInputStream(new File("新垣结衣.jpg"));
    //写出文件
        byte[] buffer = new byte[1024];
        int len;
        while ((len=fis.read(buffer))!=-1){
            os.write(buffer,0,len);
        }
        //确定服务器接收完毕后,才能断开连接
        InputStream inputStream1= socket.getInputStream();
        ByteArrayOutputStream baos=new ByteArrayOutputStream();
        byte[] buffer2=new byte[2048];
        int len2;
        while ((len2=inputStream1.read(buffer2))!=-1){
            baos.write(buffer2,0,len2);
        }
        System.out.println(baos.toString());
        //关闭连接
        baos.close();
        inputStream1.close();
        fis.close();;
        os.close();
        socket.close();
    }

服务端:

    public static void main(String[] args) throws IOException {
    //我有一个地址
        ServerSocket serverSocket=new ServerSocket(9000);
    //监听客户端的链接
        Socket socket=serverSocket.accept();//阻塞式监听,会一直等待客户端连接
    //获取输入流
        InputStream is=socket.getInputStream();
    //获取输出流
        FileOutputStream fos=new FileOutputStream(new File("receive.jpg"));
        byte[]buffer= new byte [1024];
        int len;
        while ((len=is.read(buffer))!=-1){
            fos.write(buffer,0,len);
        }
    //通知客户端我接收完毕了
        OutputStream os=socket.getOutputStream();
        os.write("我接受好了,拜拜了您嘞".getBytes());
    //关闭连接
        fos.close();
        is.close();
        socket.close();
        serverSocket.close();
    }

如果我们只是这样这样写完的话,我们会发现一个奇怪的现象如下:

20200917113753167.gif

之前我们的客户端都是发完消息之后就直接关闭了,并且服务端也是接收到消息之后也不做其他的处理,所以整个的通信是能够正常结束的.


但是现在因为我们需要服务器在接收完数据之后告诉客户端我已经成功接收到数据了,你可以关闭连接了.所以客户端这边也是在等待接收服务端数据的状态所以这样就形成了思死锁的状态.就如下图所示:


2020091711383690.png

所以我们在客户端发送完数据之后需要断开socket的输出连接,否则服务端还是无法接收到客户端的信息的.


在客户端发送数据的代码后面添加这一段代码:


//      通知服务器,我已经结束了
        socket.shutdownOutput();//我已经传输完了


这样之后我们的文件上传就实现了,效果如下:


20200917113807130.gif


相关文章
|
1月前
|
安全 网络安全 网络虚拟化
【软件设计师备考 专题 】常用网络设备和各类通信设备(一)
【软件设计师备考 专题 】常用网络设备和各类通信设备
97 2
|
1月前
|
移动开发 网络协议 安全
网络面试题:什么是 TCP/IP?
网络面试题:什么是 TCP/IP?
43 0
网络面试题:什么是 TCP/IP?
|
1月前
|
监控 负载均衡 网络协议
TCP重传与超时机制:解锁网络性能之秘
TCP重传与超时机制:解锁网络性能之秘
68 0
|
4天前
|
存储 网络协议 关系型数据库
Python从入门到精通:2.3.2数据库操作与网络编程——学习socket编程,实现简单的TCP/UDP通信
Python从入门到精通:2.3.2数据库操作与网络编程——学习socket编程,实现简单的TCP/UDP通信
|
19天前
|
安全 网络安全 SDN
虚拟网络设备的真正使命:实现有控制的通信
虚拟网络设备确实提供了强大的网络隔离能力🛡️,但这种隔离本身并不是最终目的。实际上,更重要的是通过这种隔离能力实现有控制的通信🎛️,以满足特定的业务需求、安全要求和性能标准。换句话说,网络隔离是手段,而有控制的通信才是目的🎯。
虚拟网络设备的真正使命:实现有控制的通信
|
20天前
|
网络协议 安全 网络性能优化
|
30天前
|
缓存 网络协议 数据库连接
【底层服务/编程功底系列】「网络通信体系」深入探索和分析TCP协议的运输连接管理的核心原理和技术要点
【底层服务/编程功底系列】「网络通信体系」深入探索和分析TCP协议的运输连接管理的核心原理和技术要点
24 0
|
1月前
|
存储 运维 安全
云擎技术:通信网络单元定级备案指南
简介: 通信网络单元定级备案是指相关基础电信企业、增值电信企业要对本单位管理、运行的公用通信网和互联网及其各类信息系统进行单元划分,按照《通信网络安全防护管理办法》(工业和信息化部令第11号)的规定开展定级工作,并在工业和信息化部“通信网络安全防护管理系统”报送各单元的定级信息。
34 2
|
1月前
|
安全 网络安全 网络虚拟化
【软件设计师备考 专题 】常用网络设备和各类通信设备(三)
【软件设计师备考 专题 】常用网络设备和各类通信设备
36 0
|
1月前
|
安全 算法 网络安全
【软件设计师备考 专题 】常用网络设备和各类通信设备(二)
【软件设计师备考 专题 】常用网络设备和各类通信设备
41 2