Java TCP UDP网络传输协议 图片+代码 超详细解答!!

网络协议及编程示例

网络协议这边列举两个较为常用传输层的协议 TCP UDP

TCP

特点

点对点的通信方式,一般应用于客户端和服务端

传输前需要建立TCP连接,形成数据传输通道

连接时需要先进行三次握手,确保连接双方存在,连接可靠性高

传输的数据量大

传输完毕需要释放已建立的连接,进行四次挥手,效率较低

例如:打电话

三次握手

请添加图片描述

为什么采取三次握手,不是一次两次,不是四次五次呢?

因为第一次和第二次握手之后,连接保证两者存在的可靠性相对较低,第三次握手之后可靠性提升很大,可达到99%,第四次第五次之后虽说可靠性会提升,但是提升的很少,可靠性再第三次已经足够,为了耗费少一些的网络资源,故TCP选择三次握手,即可靠也尽量减少了网络资源的消耗

四次挥手

请添加图片描述

断开连接的请求,客户端和服务端都可以发送,断开连接的方式为四次挥手,通过四次挥手确定连接已经断开

TCP网络编程例

再网络发送文件时,对于中文,一般使用ByteArrayOutputStream,先把读取的字节存放至ByteArrayOutputStream中,再读取
,这样可以解决中文读取乱码问题

1.客户端发送消息给服务端

服务端

public class TCPSever {
    public static void main(String[] args) {
            ServerSocket serverSocket = null;
            Socket socket = null;
            InputStream is = null;
            ByteArrayOutputStream baos = null;
            try {
                //指定服务器端口号
                serverSocket = new ServerSocket(9999);
                //服务器接收客户端的Socket
                socket = serverSocket.accept();

                //创建读取流读取客户端消息
                is = socket.getInputStream();
                //信息读取
                int len;
                byte[] buffer = new byte[20];
                baos = new ByteArrayOutputStream();
                while ((len = is.read(buffer)) != -1) {
                    //使用ByteArrayOutputStream,先把读取的字节存放至ByteArrayOutputStream中,再读取
                    //解决中文读取乱码问题
                    //先把字节写到ByteArrayOutputStream对象的数组中
                    baos.write(buffer,0,len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //读取ByteArrayOutputStream对象中的数据,并显示在控制台上
                System.out.println(baos.toString());

                //资源关闭
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    }
}

客户端

public class TCPClient {
    public static void main(String[] args) {
        Socket socket = null;
        OutputStream os = null;

        try {
            //创建IP
            InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
            //指定客户端的端口号和IP 创建Socket对象
            socket = new Socket(inetAddress,9999);

            //根据Socket对象创建写出流
            os = socket.getOutputStream();
            //写出操作
            os.write("学好Java,网络编程不可少".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //资源关闭
            if (os != null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

在TCP中需要先开启服务端再开启客户端,否则会报错连接不上。

2.客户端发送文件给服务端,服务端将其保存至本地

客户端

public class Client2 {
    public static void main(String[] args) {
        Socket socket = null;
        OutputStream os = null;
        OutputStreamWriter osw = null;
        BufferedReader bfr = null;
        try {
            //创建socket
            InetAddress inetAddress = InetAddress.getLocalHost();
            socket = new Socket(inetAddress, 6666);
            //创建输出流 以及 文件读取流
            os = socket.getOutputStream();
            osw = new OutputStreamWriter(os);
            bfr = new BufferedReader(new FileReader("Test"));

            //文件读取,并进行传输
            int len;
            char[] buffer = new char[5];
            while ((len = bfr.read(buffer)) != -1) {
                osw.write(buffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }

        //资源关闭
        if (bfr != null){
            try {
                bfr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (osw != null){
            try {
                osw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (socket != null){
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("客户端启动成功");
    }
}

服务端

public class Server2 {

    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream is = null;
        BufferedWriter bfw = null;
        InputStreamReader isr = null;
        try {
            //指定自身端口号
            serverSocket = new ServerSocket(6666);
            System.out.println("服务端启动成功,等待客户端发送请求......");
            //接收客户端socket
            socket = serverSocket.accept();
            System.out.println("收到客户端发送请求");

            //创建流对象
            is = socket.getInputStream();
            bfw = new BufferedWriter(new FileWriter("destTest.txt"));
            //转换流转换为字符流
            isr = new InputStreamReader(is);

            int len;
            char[] buffer = new char[5];
            while ((len = isr.read(buffer)) != -1) {
                bfw.write(buffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //资源关闭
            if (bfw != null) {
                try {
                    bfw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (isr != null) {
                try {
                    isr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("文件传输成功");
    }

}
3.客户端发送消息给服务端,服务端收到并返回发送成功给客户端。发送完成关闭连接

客户端

public class Client3 {
    public static void main(String[] args) {
        Socket socket = null;
        OutputStream os = null;
        BufferedInputStream bfis = null;
        InputStream is = null;
        ByteOutputStream baos = null;
        OutputStream os2 = null;
        try {
            System.out.println("客户端启动......");
            //创建socket
            socket = new Socket(InetAddress.getLocalHost(), 6666);

            //创建流
            os = socket.getOutputStream();
            bfis = new BufferedInputStream(new FileInputStream("test4.jpg"));

            //文件写出
            int len;
            byte[] buffer = new byte[1024];
            while ((len = bfis.read(buffer)) != -1) {
                os.write(buffer,0,len);
            }
            socket.shutdownOutput();

            //服务端返回消息读入
            is = socket.getInputStream();
            baos = new ByteOutputStream();
            while ((len = is.read(buffer)) != -1){
                baos.write(buffer,0,len);
            }
            System.out.println(baos.toString());

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //资源关闭
            if (bfis != null){
                try {
                    bfis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (os != null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (baos != null) {
                baos.close();
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (os2 != null){
                try {
                    os2.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


    }
}

服务端

public class Server3 {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        BufferedInputStream bfis = null;
        BufferedOutputStream bfos = null;
        OutputStream os = null;
        ByteArrayOutputStream baos = null;
        InputStream is = null;
        try {
            System.out.println("服务端启动......");
            //得到socket
            serverSocket = new ServerSocket(6666);
            socket = serverSocket.accept();

            //创建流
            bfis = new BufferedInputStream(socket.getInputStream());
            bfos = new BufferedOutputStream(new FileOutputStream("test5.jpg"));
            //文件读取写入
            int len;
            byte[] buffer = new byte[1024];
            while ((len = bfis.read(buffer)) != -1) {
                bfos.write(buffer,0,len);
            }

            os = socket.getOutputStream();
            os.write("服务器已接收到,正在关闭连接.....".getBytes());
            socket.shutdownOutput();

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            if (bfis != null) {
                try {
                    bfis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (bfos!=null) {
                try {
                    bfos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (baos != null){
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

在使用旧版IO的客户端和服务端数据交换时(因为read操作是阻塞式的)用socket的流做写出操作时,写完一定要关闭socket,否则接受时不能判断是否已经写出完,会一直在while循环中等待一方的输入;使用NIO则可以解决这一问题

测试:客户端发送英文给服务端,服务端将其转换为大写发送回客户端

客户端

public class Client4 {
    public static void main(String[] args) {
        System.out.println("客户端启动...");
        Scanner scanner = new Scanner(System.in);
        Socket socket = null;
        BufferedInputStream bfis = null;
        OutputStream os = null;
        ByteArrayOutputStream baos = null;
        try {
            socket = new Socket(InetAddress.getLocalHost(), 6666);

            //创建输出流
            os = socket.getOutputStream();

            System.out.print("请输入:");
            //输出
            os.write(scanner.next().getBytes());

            socket.shutdownOutput();

            //接收服务器返回并输出
            bfis = new BufferedInputStream(socket.getInputStream());
            int len;
            byte[] buffer = new byte[1024];
            baos = new ByteArrayOutputStream();
            while ((len = bfis.read(buffer)) != -1) {
                baos.write(buffer,0,len);
            }
            System.out.println(baos.toString());

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //资源关闭
            if (socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (bfis != null){
                try {
                    bfis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (baos != null){
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (os != null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

服务端

public class Server4 {
    public static void main(String[] args){
        System.out.println("服务端启动...");
        ServerSocket serverSocket = null;
        Socket socket = null;
        OutputStream os = null;
        BufferedInputStream bfis = null;
        ByteArrayOutputStream baos = null;
        try {
            //接收客户端socket
            serverSocket = new ServerSocket(6666);
            socket = serverSocket.accept();

            //接收
            bfis = new BufferedInputStream(socket.getInputStream());
            int len;
            byte[] buffer = new byte[1024];
            baos = new ByteArrayOutputStream();
            while ((len = bfis.read(buffer)) != -1){
                System.out.println("进入循环");
                baos.write(buffer,0,len);
            }

            System.out.println("服务器处理完毕,正在返回...");
            //返回
            os = socket.getOutputStream();
            os.write(baos.toString().toUpperCase().getBytes());
            socket.shutdownOutput();

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            if (serverSocket != null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (baos != null){
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (bfis != null){
                try {
                    bfis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (os != null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

UDP

特点

将数据、源、目的封装成数据包,不需要建立连接

发送结束不需要释放资源,开销小,传输速度快但不可靠

传输内容较少一次最多64K

可以广播发送

例如:发电报,发短信

UDP网络编程例

接收端

public class Sender {

    public static void main(String[] args) {
        DatagramSocket socket = null;
        try {
            //创建socket
            socket = new DatagramSocket();
            //创建发送的数据报,并指明发送IP和端口号
            byte[] data = "UDP发送的数据".getBytes();
            InetAddress inetAddress = InetAddress.getLocalHost();
            DatagramPacket datagramPacket = new DatagramPacket(data, 0, data.length, inetAddress, 6666);
            //通过socket发送数据报
            socket.send(datagramPacket);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //资源关闭
            socket.close();
        }
    }

}

发送端

public class Sender {

    public static void main(String[] args) {
        DatagramSocket socket = null;
        try {
            //创建socket
            socket = new DatagramSocket();
            //创建发送的数据报,并指明发送IP和端口号
            byte[] data = "UDP发送的数据".getBytes();
            InetAddress inetAddress = InetAddress.getLocalHost();
            DatagramPacket datagramPacket = new DatagramPacket(data, 0, data.length, inetAddress, 6666);
            //通过socket发送数据报
            socket.send(datagramPacket);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //资源关闭
            socket.close();
        }
    }

}

发送端

public class Sender {

    public static void main(String[] args) {
        DatagramSocket socket = null;
        try {
            //创建socket
            socket = new DatagramSocket();
            //创建发送的数据报,并指明发送IP和端口号
            byte[] data = "UDP发送的数据".getBytes();
            InetAddress inetAddress = InetAddress.getLocalHost();
            DatagramPacket datagramPacket = new DatagramPacket(data, 0, data.length, inetAddress, 6666);
            //通过socket发送数据报
            socket.send(datagramPacket);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //资源关闭
            socket.close();
        }
    }

}

由于UDP协议的特性,先开启发送端,再开启接收端是不会报错的,只是收不到消息;而在TCP中,先开启客户端(不论做发送还是接收)再开启服务端都会进行三次握手导致报错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值