看了这篇网络编程,就能够和面试官聊聊了

网络编程

一、网络编程的基本概念
二、IP地址及端口号
三、通讯协议
四、TCP通讯代码实践
    4.1消息传递
    4.2文件上传
五、UDP通讯代码
    5.1 UDP实现消息发送
    5.2 使用UDP循环发送和接收消息
    5.3使用UDP实现聊天
复制代码

一、网络编程的基本概念

引例java

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

在这种状况下,身处异地的朋友若是要进行通讯,必须同时知足如下条件服务器

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

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

慢慢的,随着科技的发展,咱们有手机通讯、QQ聊天和微信聊天等多种通讯方式,采用这些方式咱们能够更便捷的进行通讯,可是不管是那种方式,通讯过程当中老是须要这样两个元素:地址传输过程网络

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

一、IP地址和端口号并发

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

二、传输协议ide

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

二、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" # 查看指定的端口
复制代码

三、通讯协议

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

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

  • TCP

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

  • UDP

UDP是一种无链接的传输协议,无需创建链接就能够发送数据包

  • IP

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

TCP和UDP对比

TCP能够类比于打电话,它具备如下特色

  • 在数据传输前,须要创建链接(三次握手),因此链接稳定可靠
  • 有客户端、服务端的概念,客户端发送,服务端接收
  • 传输完成后,会释放链接(四次挥手)

UDP能够类比于发短信,它具备如下特色

  • 数据传输前,不须要创建链接,因此不可靠,不稳定
  • 客户端和服务端没有明确界限,客户端和服务端均可以进行收/发
  • 不须要创建链接,因此速度较快

四、TCP通讯代码实践

TCP网络编程须要如下Java类

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

Socket:实现客户端的套接字,创建链接,套接字就是两台机器间通信的端点

ServerSocket:实现服务端的套接字

4.1消息传递

客户端

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

2.创建Socket链接

3.发送消息

public class TcpClient {
    public static void main(String[] args) throws IOException {
        Socket socket=null;
        OutputStream os=null;
        try {
            //一、获得服务端的地址,端口号
            InetAddress inetAddress=InetAddress.getByName("127.0.0.1");
            int port=9898;
            //二、创建Socket链接
          socket=new Socket(inetAddress,port);
            //三、发送消息
            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)把等待链接的方法包裹起来,重复接收消息

三、获取发送端的消息

public class TcpServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket=null;
        Socket socket=null;
        InputStream is=null;
        ByteArrayOutputStream baos=null;
        try {
            //一、设置本身的端口号
            serverSocket=new ServerSocket(9898);
            //二、等待客户端的链接
            socket=serverSocket.accept();
            //三、读取客户端的消息
            is=socket.getInputStream();
            baos=new ByteArrayOutputStream();
            byte[] buffer=new byte[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.关闭链接资源

public class TcpFileClient {
    public static void main(String[] args) throws Exception {

        //一、建立链接
        Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9987);
        //二、定义一个输出流用于通讯
        OutputStream os = socket.getOutputStream();
        FileInputStream fis = new FileInputStream(new File("simon.png"));
        byte[] buffer = new byte[1024];
        int len;
        while ((len = fis.read(buffer)) != -1) {
            os.write(buffer, 0, len);
        }
        //三、通知服务器,我已经结束了
        socket.shutdownOutput();

        //肯定服务器接收完毕,才能够断开链接,这一段代码主要是接收服务端发出的结束信息
       InputStream inputStream= socket.getInputStream();
        byte[] buffer2=new byte[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.关闭资源

public class TcpFileServerDemo02 {
    public static void main(String[] args) throws Exception {
        //设置端口号
        ServerSocket serverSocket=new ServerSocket(9987);
        //等待链接
        Socket socket=serverSocket.accept();
        //获取输入流
        InputStream is=socket.getInputStream();
        //文件输出
        FileOutputStream fos=new FileOutputStream(new File("snow.png"));
        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();
    }
}

复制代码

五、UDP通讯代码

UDP不须要链接,可是须要知道对方的地址和端口号,主要用到了如下Java类

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

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

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

5.1 UDP实现消息发送

客户端

  • 创建链接
  • 建立数据包
  • 发送数据包
public class UdpClientDemo1 {
    public static void main(String[] args) throws Exception {
        //一、创建链接(这个端口号是客户端的)
        DatagramSocket datagramSocket=new DatagramSocket(9888);
        //二、创建数据包
        String msg="hello,Simon";
        InetAddress inetAddress=InetAddress.getByName("127.0.0.1");
        //数据,数据的起始位置,要发送的地址与端口号
        DatagramPacket datagramPacket=new DatagramPacket(msg.getBytes(),0,msg.getBytes().length,inetAddress,9887);
        //三、发送数据包
        datagramSocket.send(datagramPacket);
        //四、关闭数据流
        datagramSocket.close();

    }
}
复制代码

服务端

  • 创建链接
  • 接收数据
public class UdpServerDemo2 {
    public static void main(String[] args) throws Exception{
        //创建链接,开放的端口
        DatagramSocket datagramSocket=new DatagramSocket(9887);
        //接收数据包
        byte[] buffer=new byte[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"),退出便可。这样就能够达到循环发送和接收消息。

客户端

public class UdpSend {
    public static void main(String[] args) throws Exception {
        //一、创建链接
        DatagramSocket datagramSocket=new DatagramSocket(9888);
        //二、建立数据包,从键盘输入
        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);
            //三、发送数据
            datagramSocket.send(datagramPacket);
            if(s.equals("bye")){
                break;
            }
        }
        //四、关闭数据
        datagramSocket.close();
        }
}

复制代码

服务端

public class UdpReceive{
    public static void main(String[] args) throws Exception {
        //一、创建链接
        DatagramSocket datagramSocket=new DatagramSocket(9887);
        while (true){
           //二、接收数据包
           byte[] buffer=new byte[1024];
            DatagramPacket datagramPacket=new DatagramPacket(buffer,0,buffer.length);
            datagramSocket.receive(datagramPacket);
            //三、断开链接
            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实现聊天,则客户端和服务端(其实不存在客户端和服务端的概念)既须要接收信息也须要发送消息,这就须要多线程的支持了。

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

发送类

public class TalkSend implements Runnable {
    DatagramSocket datagramSocket = null;
    BufferedReader bufferedReader = null;

    private int fromPort;
    private int toPort;
    private String toIp;

    public TalkSend(int fromPort,int toPort,String toIp){
        this.fromPort=fromPort;
        this.toPort=toPort;
        this.toIp=toIp;

        //一、创建链接
        try {
            datagramSocket = new DatagramSocket(fromPort);
            //二、建立数据包,从键盘输入
            bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        while (true) {
            try {
                String s = bufferedReader.readLine();
                DatagramPacket datagramPacket = new DatagramPacket(s.getBytes(), 0, s.getBytes().length, new InetSocketAddress(toIp,toPort));
                //三、发送数据
                datagramSocket.send(datagramPacket);
                if (s.equals("bye")) {
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        //四、关闭数据
        datagramSocket.close();
    }
}
复制代码

接收类

public class TalkReceive implements Runnable{
    DatagramSocket datagramSocket=null;
    private int port;
    private String msgFrom;

    public TalkReceive(int port,String msgFrom) {
        this.port=port;
        this.msgFrom=msgFrom;

        //一、创建链接
        try {
            datagramSocket=new DatagramSocket(port);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



    @Override
    public void run() {
        while (true){
            try {
                //二、接收数据包
                byte[] buffer=new byte[1024];
                DatagramPacket datagramPacket=new DatagramPacket(buffer,0,buffer.length);
                datagramSocket.receive(datagramPacket);
                //三、断开链接
                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

public class TalkStudent {
    public static void main(String[] args) {
        new Thread(new TalkSend(7777,9999,"localhost")).start();
        new Thread(new TalkReceive(8888,"小包")).start();
    }
}
复制代码

用户类2

public class TalkTeacher {
    public static void main(String[] args){
        new Thread(new TalkSend(5555,8888,"localhost")).start();
        new Thread(new TalkReceive(9999,"小郎")).start();
    }
}
复制代码
相关文章
相关标签/搜索