网络通信学习笔记(三)---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


相关文章
|
25天前
|
网络协议 安全 5G
网络与通信原理
【10月更文挑战第14天】网络与通信原理涉及众多方面的知识,从信号处理到网络协议,从有线通信到无线通信,从差错控制到通信安全等。深入理解这些原理对于设计、构建和维护各种通信系统至关重要。随着技术的不断发展,网络与通信原理也在不断演进和完善,为我们的生活和工作带来了更多的便利和创新。
62 3
|
1月前
|
Ubuntu 网络安全 图形学
Ubuntu学习笔记(二):ubuntu20.04解决右上角网络图标激活失败或者消失,无法连接有线问题。
在Ubuntu 20.04系统中解决网络图标消失和无法连接有线网络问题的方法,其中第三种方法通过检查并确保Windows防火墙中相关服务开启后成功恢复了网络连接。
459 0
Ubuntu学习笔记(二):ubuntu20.04解决右上角网络图标激活失败或者消失,无法连接有线问题。
|
8天前
|
传感器 自动驾驶 物联网
探秘 5G 核心网络之 5G RAN:开启高速通信新时代
探秘 5G 核心网络之 5G RAN:开启高速通信新时代
29 4
|
16天前
|
网络协议 算法 网络性能优化
计算机网络常见面试题(一):TCP/IP五层模型、TCP三次握手、四次挥手,TCP传输可靠性保障、ARQ协议
计算机网络常见面试题(一):TCP/IP五层模型、应用层常见的协议、TCP与UDP的区别,TCP三次握手、四次挥手,TCP传输可靠性保障、ARQ协议、ARP协议
|
23天前
|
Web App开发 缓存 网络协议
不为人知的网络编程(十八):UDP比TCP高效?还真不一定!
熟悉网络编程的(尤其搞实时音视频聊天技术的)同学们都有个约定俗成的主观论调,一提起UDP和TCP,马上想到的是UDP没有TCP可靠,但UDP肯定比TCP高效。说到UDP比TCP高效,理由是什么呢?事实真是这样吗?跟着本文咱们一探究竟!
49 10
|
1月前
|
机器学习/深度学习 人工智能 算法
|
19天前
|
物联网 5G 数据中心
|
30天前
|
网络协议 安全 数据安全/隐私保护
网络协议:互联网通信的基石
【10月更文挑战第12天】
70 1
|
1月前
|
网络协议 Linux 应用服务中间件
Socket通信之网络协议基本原理
【10月更文挑战第10天】网络协议定义了机器间通信的标准格式,确保信息准确无损地传输。主要分为两种模型:OSI七层模型与TCP/IP模型。
|
12天前
|
边缘计算 5G 数据处理
5G网络能耗管理:绿色通信的实践
【10月更文挑战第30天】
32 0