美文网首页Java
金秋十月当然是分享下重磅技术文——网络编程大揭秘

金秋十月当然是分享下重磅技术文——网络编程大揭秘

作者: Java斗帝之路 | 来源:发表于2020-10-06 12:55 被阅读0次

目录

1、网络编程的基本概念

2、IP地址及端口号

3、通信协议

4、TCP通信代码实践

4.1消息传递

4.2文件上传

5、UDP通信代码实践

5.1 UDP实现消息发送

5.2 使用UDP循环发送和接收消息

5.3使用UDP实现聊天

1、网络编程的基本概念

引例

在学习网络编程之前,我们先看这样一个例子。一般处于我们这个年龄段的同学,大都经历过写信/寄信的经历,在写信的时候,我们一般都需要明确发送的地址、联系人信息以及所在地区的邮编,邮递员可以根据这上面的信息找到接收信件的人,接收人在阅读过信件的内容后可以以同样的方式回信,这样就使得身处异地的朋友间可以进行通信。

在这种情况下,身处异地的朋友如果要进行通信,必须同时满足以下条件

1.接收人的所在地区及详细的住址

2.需要有快递员接收并发送

慢慢的,随着科技的发展,我们有手机通信、QQ聊天和微信聊天等多种通信方式,采用这些方式我们可以更便捷的进行通信,但是无论是那种方式,通信过程中总是需要这样两个元素:地址及传输过程。

在网络通信中,这两个元素可以使用更专业的名词来代替:

1、IP地址和端口号

IP地址可以帮助我们找到通信的接收方,端口号则可以帮助我们找到计算机中的具体应用,如QQ、微信等

2、传输协议

协议是为了帮助我们更好的进行传输,如TCP、UDP、FTP、SMTP和HTTP协议等

2、IP地址及端口号

IP地址是互联网协议地址,它是一种统一的地址格式,互联网中的每一台主机都会有一个逻辑地址。在计算机网络中,localhost(意为“本地主机”,指“这台计算机”)是给回的一个标准主机名,相对应的IP地址为127.0.0.1

通过IP地址,我们就可以连接到指定的计算机了,但是如果要访问目标计算机中的某个应用程序,还需要知道端口号。在计算中,不同的应用程序就是通过端口号来进行区分的。

在网络编程中,可以使用InetAddress进行主机名解析和反向解析,即给定确定的主机名,返回确定的IP地址;给定IP地址,返回主机名

localhost解析为127.0.0.1

127.0.0.1反向解析为localhost

NOTE:不同协议的端口是可以重复的,如UDP和TCP

端口的查询操作

netstat -ano#查看所有的端口netstat -ano | findstr"XXX"# 查看指定的端口

3、通信协议

IP地址及端口号解决了通信过程中的地址问题,但是在计算机中,我们还要解决如何通信问题,所谓通信就是计算机间如何交流,而通信协议就是将计算机双方遵循的一种规则和约定(如同普通话、英语),它可以通过通信信道将处于不同地理位置的设备连接起来,能够实现信息的交换和资源共享。

在计算机网络中,常用的协议就是TCP/IP,它是协议簇,由多个子协议组成了,如我们常见的TCP、IP、UDP、ARP等,我们主要讲解网络编程中常用的TCP、UDP和IP

TCP

TCP协议是一种传输协议,面向连接、可靠的、基于字节流的传输层通信协议

UDP

UDP是一种无连接的传输协议,无需建立连接就可以发送数据包

IP

IP协议整个TCP/IP协议族的核心,对上可载送传输层各种协议的信息,例如TCP、UDP等;对下可将IP信息包放到链路层,通过以太网等各种技术来传送。

TCP和UDP对比

TCP可以类比于打电话,它具有以下特点

在数据传输前,需要建立连接(三次握手),所以连接稳定可靠

有客户端、服务端的概念,客户端发送,服务端接收

传输完成后,会释放连接(四次挥手)

UDP可以类比于发短信,它具有以下特点

数据传输前,不需要建立连接,所以不可靠,不稳定

客户端和服务端没有明确界限,客户端和服务端都可以进行收/发

不需要建立连接,所以速度较快

4、TCP通信代码实践

TCP网络编程需要以下Java类

InetAddress:表示IP协议的地址,可以解析IP地址和主机名

Socket:实现客户端的套接字,建立连接,套接字就是两台机器间通讯的端点

ServerSocket:实现服务端的套接字

4.1消息传递

客户端

1.拿到服务端的地址及端口,InetAddress

2.建立Socket连接

3.发送消息

publicclassTcpClient {publicstaticvoidmain(String[] args)throws IOException {        Socket socket=null;        OutputStream os=null;try {//1、得到服务端的地址,端口号            InetAddress inetAddress=InetAddress.getByName("127.0.0.1");int port=9898;//2、建立Socket连接          socket=new Socket(inetAddress,port);//3、发送消息            os=socket.getOutputStream();            os.write("hello,Simon".getBytes());        }catch (Exception e){            e.printStackTrace();        }finally {//关闭资源

           os.close();

           socket.close();

        } 

    }

}

服务端

1.用ServerSocket设置自己的端口号

2.等待连接,Socket

2.1:可以等待一次连接,接收到消息后关闭

2.2:等待多次连接,用while(true)把等待连接的方法包裹起来,重复接收消息

3、获取发送端的消息

publicclassTcpServer {publicstaticvoidmain(String[] args) throws IOException {        ServerSocket serverSocket=null;        Socket socket=null;        InputStreamis=null;        ByteArrayOutputStream baos=null;try {//1、设置自己的端口号            serverSocket=new ServerSocket(9898);//2、等待客户端的连接            socket=serverSocket.accept();//3、读取客户端的消息is=socket.getInputStream();            baos=new ByteArrayOutputStream();byte[] buffer=newbyte[1024];int len;while ((len=is.read(buffer))!=-1){                baos.write(buffer,0,len);            }            System.out.print(baos.toString());        }catch (Exception e){            e.printStackTrace();        }finally {            baos.close();is.close();

            socket.close();

            serverSocket.close();

        }

    }

}

4.2文件上传

客户端

1.创建一个连接

2.创建一个字节输出流用于通信

创建一个文件输入流用于接收文件,然后将接收后的文件给字节输出流用于通信

3.输出结束后,调用shutdownInput方法通知服务端已经发送完毕

4.关闭连接资源

publicclassTcpFileClient {publicstaticvoidmain(String[] args) throws Exception {//1、创建连接        Socket socket =new Socket(InetAddress.getByName("127.0.0.1"),9987);//2、定义一个输出流用于通信        OutputStream os = socket.getOutputStream();        FileInputStream fis =new FileInputStream(new File("simon.png"));byte[] buffer =newbyte[1024];int len;while ((len = fis.read(buffer)) !=-1) {            os.write(buffer,0, len);        }//3、通知服务器,我已经结束了        socket.shutdownOutput();//确定服务器接收完毕,才可以断开连接,这一段代码主要是接收服务端发出的结束信息       InputStream inputStream= socket.getInputStream();byte[] buffer2=newbyte[1024];        ByteArrayOutputStream baos=new ByteArrayOutputStream();int len2;while ((len2=inputStream.read(buffer2))!=-1){            baos.write(buffer2,0,len2);        }        System.out.print(baos.toString());//关闭连接

        baos.close();

        inputStream.close();

        os.close();

        fis.close();

        socket.close();

    }

}

服务端

1.创建一个连接用于等待客户端的接入

2.创建一个输入流

创建一个文件输出流,将输入流输出

3.关闭资源

publicclassTcpFileServerDemo02 {publicstaticvoidmain(String[] args) throws Exception {//设置端口号        ServerSocket serverSocket=new ServerSocket(9987);//等待连接        Socket socket=serverSocket.accept();//获取输入流        InputStreamis=socket.getInputStream();//文件输出        FileOutputStream fos=new FileOutputStream(new File("snow.png"));byte[] buffer=newbyte[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();

    }

}

5、UDP通信代码实践

UDP不需要连接,但是需要知道对方的地址和端口号,主要用到了以下Java类

DatagramPacket:表示数据包,用于实现无连接分组传送服务

DatagramSocket:表示用于发送和接收数据报的套接字

UDP是不存在客户端和服务端的概念,但是为了编程模拟方便,我们假定存在客户端和服务端

5.1 UDP实现消息发送

客户端

建立连接

创建数据包

发送数据包

publicclassUdpClientDemo1 {publicstaticvoidmain(String[] args)throws Exception {//1、建立连接(这个端口号是客户端的)        DatagramSocket datagramSocket=new DatagramSocket(9888);//2、建立数据包        String msg="hello,Simon";        InetAddress inetAddress=InetAddress.getByName("127.0.0.1");//数据,数据的起始位置,要发送的地址与端口号        DatagramPacket datagramPacket=new DatagramPacket(msg.getBytes(),0,msg.getBytes().length,inetAddress,9887);//3、发送数据包        datagramSocket.send(datagramPacket);//4、关闭数据流

        datagramSocket.close();

    }

}

服务端

建立连接

接收数据

publicclassUdpServerDemo2 {publicstaticvoidmain(String[] args) throws Exception{//建立连接,开放的端口        DatagramSocket datagramSocket=new DatagramSocket(9887);//接收数据包byte[] buffer=newbyte[1024];        DatagramPacket datagramPacket=new DatagramPacket(buffer,0,buffer.length);        datagramSocket.receive(datagramPacket);//打印数据包信息        System.out.println(datagramPacket.getAddress());        System.out.println(datagramPacket.getPort());        System.out.println(new String(datagramPacket.getData()));//关闭连接

        datagramSocket.close();

    }

5.2 使用UDP循环发送和接收消息

使用while(true)方法将客户端中的发送数据和接收数据包裹起来,只要当他们满足一定的条件时(如输入的字符串为"bye"),退出即可。这样就可以达到循环发送和接收消息。

客户端

publicclassUdpSend {publicstaticvoidmain(String[] args) throws Exception {//1、建立连接        DatagramSocket datagramSocket=new DatagramSocket(9888);//2、创建数据包,从键盘输入        InetAddress inetAddress=InetAddress.getByName("127.0.0.1");int port=9887;        BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(System.in));while (true){            String s=bufferedReader.readLine();            DatagramPacket datagramPacket=new DatagramPacket(s.getBytes(),0,s.getBytes().length,inetAddress,9887);//3、发送数据            datagramSocket.send(datagramPacket);if(s.equals("bye")){break;            }        }//4、关闭数据

        datagramSocket.close();

        }

}

服务端

publicclassUdpReceive{publicstaticvoidmain(String[] args) throws Exception {//1、建立连接        DatagramSocket datagramSocket=new DatagramSocket(9887);while (true){//2、接收数据包byte[] buffer=newbyte[1024];            DatagramPacket datagramPacket=new DatagramPacket(buffer,0,buffer.length);            datagramSocket.receive(datagramPacket);//3、断开连接byte[] data=datagramPacket.getData();            String receiveData=new String(data,0,data.length);            System.out.println(receiveData);if(receiveData.equals("bye")){break;

            }

        }

        datagramSocket.close();

    }

}

5.3使用UDP实现聊天

使用UDP实现聊天,则客户端和服务端(其实不存在客户端和服务端的概念)既需要接收信息也需要发送消息,这就需要多线程的支持了。

我们首先构造两个接收类和发送的线程类,然后构造俩个用户类进行通信。

发送类

publicclassTalkSendimplementsRunnable {    DatagramSocket datagramSocket =null;    BufferedReader bufferedReader =null;privateint fromPort;privateint toPort;private String toIp;publicTalkSend(int fromPort,int toPort,String toIp){this.fromPort=fromPort;this.toPort=toPort;this.toIp=toIp;//1、建立连接try {            datagramSocket =new DatagramSocket(fromPort);//2、创建数据包,从键盘输入            bufferedReader =new BufferedReader(new InputStreamReader(System.in));        }catch (SocketException e) {            e.printStackTrace();        }    }@Overridepublicvoidrun() {while (true) {try {                String s = bufferedReader.readLine();                DatagramPacket datagramPacket =new DatagramPacket(s.getBytes(),0, s.getBytes().length,new InetSocketAddress(toIp,toPort));//3、发送数据                datagramSocket.send(datagramPacket);if (s.equals("bye")) {break;                }            }catch (IOException e) {                e.printStackTrace();            }        }//4、关闭数据

        datagramSocket.close();

    }

}

接收类

publicclassTalkReceiveimplementsRunnable{    DatagramSocket datagramSocket=null;privateint port;private String msgFrom;publicTalkReceive(int port,String msgFrom)  {this.port=port;this.msgFrom=msgFrom;//1、建立连接try {            datagramSocket=new DatagramSocket(port);        }catch (Exception e) {            e.printStackTrace();        }    }@Overridepublicvoidrun() {while (true){try {//2、接收数据包byte[] buffer=newbyte[1024];                DatagramPacket datagramPacket=new DatagramPacket(buffer,0,buffer.length);                datagramSocket.receive(datagramPacket);//3、断开连接byte[] data=datagramPacket.getData();                String receiveData=new String(data,0,data.length);                System.out.println(msgFrom+": "+receiveData);if(receiveData.equals("bye")){break;                }            }catch (Exception e) {

                e.printStackTrace();

            }

        }

        datagramSocket.close();

    }

}

用户类1

publicclassTalkStudent {publicstaticvoidmain(String[] args) {new Thread(new TalkSend(7777,9999,"localhost")).start();new Thread(new TalkReceive(8888,"小包")).start();

    }

}

用户类2

publicclassTalkTeacher {publicstaticvoidmain(String[] args){new Thread(new TalkSend(5555,8888,"localhost")).start();new Thread(new TalkReceive(9999,"小郎")).start();

    }

}

觉得此文写的还不错的朋友可以转发+关注下小编哦,持续分享技术系列文章中!

看完三件事❤️

如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:

点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。

关注公众号 『 Java斗帝 』,不定期分享原创知识。

同时可以期待后续文章ing🚀

相关文章

网友评论

    本文标题:金秋十月当然是分享下重磅技术文——网络编程大揭秘

    本文链接:https://www.haomeiwen.com/subject/adltpktx.html