Java-网络编程

计算机网络是通过传输介质通信设施网络通信协议,把各种网络设备互相连接起来,实现资源共享和数据传输的系统。网络编程是实现互联网上的多个设备之间进行数据传输

网络协议

网络协议是用来规定数据传输的规则,为了统一网络传输的标准,国际标准化组织定义了OSI模型(开放系统互联参考模型),但由于OSI模型的协议比较复杂,所以并没有得到广泛的应用,而在实际应用中一般采用TCP/IP模型。

网络通信的要素

ip地址
端口号   
     端口分类:
        公有端口 0~1023
             HTTP : 80
             HTTPS : 443
             FTP : 21
             Telent : 23
        程序注册端口:1024~49151 分配用户或者程序
           tomcat:8080
           mysql:3306
           Orcal:1521
       动态、私有端口: 49152~65535

好比你要去某地找某个人,需要知道地址(具体到单元楼)和门牌号。

网络分层

Java-网络编程_第1张图片

TCP(Transmission COntrol Protocol)传输控制协议

TCP协议提供IP环境下数据可靠传输,通过面向连接、端对端和可靠的数据包进行传输。即它是事先为所发送的数据建立好连接通道,然后在进行数据发送。

三次握手

建立一个可靠的连接需要三次握手
Java-网络编程_第2张图片

三次握手过程说明:
第一次握手:Client发送标志位(位码) syn(建立联机)=1 随机产生序列号seq=100的数据发送给Server,Server收到syn=1则知道Client要求建立联机。
第二次握手:Server收到Client请求后确认联机信息,向Client发送ack(确认信号)=(Client的seqno+1),syn=1,随机产生序列号seqno=100的数据发送给Client。
第二次握手:Client收到ack后检查是否正确,若正确,Client再次发送ack=(Server的seq+1),Server确认后则表明连接成功。

举一个不怎么恰当的例子例:
   例如跑步比赛:将发送指令的作为客户端,参赛者为服务器
              则: 预备 是客户端发送给服务器的第一次握手
                      运动员准备好了的信息 是服务端发送给客户端的第二次握手信息
                      跑: 是客户端发送给服务器的第三次握手
四次挥手

TCP连接因为是全双工的,因此单方面断开连接是不够的。断开了发送,并不能保证不会进行接收,因此需要客户端和服务端双方都有断开连接的动作
Java-网络编程_第3张图片

第一次挥手:
当数据传输即将完成,Client向服务端发送Fin(结束信号)=1的请求关闭标志位,代表告诉Server,Client数据传输完成,准备关闭连接
第二次挥手:
Server收到FIN后,Server先发送一个ACK信号给Client,确认序号为收到的序列号+1,表达的意思为你方的请求关闭我方已收到,但我方还有数据传输未完成,待我传输完成再告诉你。
第三次挥手:
Server数据传输完成,向Client发送Fin=1,Client收到Server发送的Fin=1时,知道Server的数据传输完成,可以断开连接。
第四次挥手:Client收到Server发送的Fin=1后,向Server发送ack信号确认信息进行确认,同时把自身状态设置为time_wait状态,启动计时器。如果Server没有收到Clent发送的ack,则在计时器结束后会要求客户端再发送一次ack,当Server收到Client的ack后,Server断开连接。Client在2MLS(2倍报文最大生存时间)后没有收到Server发送的重传ack请求,则认为服务端已接收到了客户端的ack,Client断开连接。

举一个不怎么恰当的例子例:
   例如男女朋友吵架:
              则: 女:我们分手吧     是客户端发送给服务器的第一次挥手信息
                      男:嗯 好吧!   是服务端发送给客户端的第二次挥手信息
                      男:那我们分手吧   是服务端发送给客户端的第三次挥手信息
                      女: 嗯 再见!  是客户端发送给服务器的第四次挥手信息

UDP(User Data Protocol) 用户数据报协议

UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。

TCP和UDP比较
UDP TCP
是否连接 无连接 面向连接
是否可靠 不可靠 可靠
连接对象个数 支持一对一、一对多、多对多和多对一交互通信 只能一对一通信
传输方式 面向报文 面向字节流
使用场景 使用与实时应用(IP电话、视频会议、直播等) 适用于要求可靠传输的应用。例如文件传输
Java网络编程

java.net包中包含的类和接口,提供了低层次的通信细节

InetAddress 类的方法

此类表示Internet协议(IP)地址。
IP地址是由IP使用的32位或128位无符号数字,构建UDP和TCP协议的低级协议。

import java.net.InetAddress;
import java.net.UnknownHostException;

public class InetAddressTest {

    public static void main(String[] args) {
        try {
            //查询本机ip地址
            InetAddress local_ip = InetAddress.getByName("localhost");
            System.out.println(local_ip);
            local_ip = InetAddress.getByName("127.0.0.1");
            System.out.println(local_ip);
            System.out.println(InetAddress.getByName("liang-PC"));
            System.out.println(InetAddress.getLocalHost());

            InetAddress baidu_ip = InetAddress.getByName("www.baidu.com");//查询网站ip地址
            System.out.println(baidu_ip);
            System.out.println(baidu_ip.getAddress());//InetAddress对象的原始IP地址
            System.out.println(baidu_ip.getHostName());//获取此IP地址的主机名。
            System.out.println(baidu_ip.getHostAddress());//返回文本显示中的IP地址字符串。
            System.out.println(baidu_ip.getCanonicalHostName());//获取此IP地址的完全限定域名。

        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }
}
InetSocketAddress类的方法

该类实现IP套接字地址(IP地址+端口号)它也可以是一对(主机名+端口号)

import java.net.InetSocketAddress;

public class InetSocketAddressTest {

    public static void main(String[] args) {
        //该类实现IP套接字地址(IP地址+端口号)它也可以是一对(主机名+端口号),在这种情况下将尝试解析主机名。
        InetSocketAddress inetSocket = new InetSocketAddress("127.0.0.1", 8080);
        System.out.println(inetSocket);

        System.out.println(inetSocket.getAddress());//获得 InetAddress
        System.out.println(inetSocket.getHostName());//
        System.out.println(inetSocket.getHostString());//地址
        System.out.println(inetSocket.getPort());//端口
    }
}

TCP简单通信

服务器端
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @deprecated : 服务器端
 * @author liang
 */
public class TcpServerDemo {

    public static void main(String[] args) {
        ServerSocket serverSocket = null;//服务器套接字
        Socket socket = null;
        InputStream inputStream = null;
        try {
            serverSocket = new ServerSocket(8888);//创建绑定到指定端口的服务器套接字
            socket = serverSocket.accept();//侦听要连接到此套接字并接受它。 该方法将阻塞直到建立连接。
            inputStream = socket.getInputStream();//获取该套接字的输入流
            //接收流数据
            byte[] bytes = new byte[1024];
            int len = 0;
            while ((len = inputStream.read(bytes)) != -1){
                String str = new String(bytes,0,len);
                System.out.println(str);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //关闭流
            if (inputStream!=null){
                try {
                    inputStream.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();
                }
            }

        }
    }

}
客户端
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
 * @deprecated : 客户端
 * @author liang
 */
public class TcpClientDemo {

    public static void main(String[] args) {
        Socket client = null;
        OutputStream outputStream = null;

        try {
            InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
            int port =8888;
            //创建流套接字并将其连接到指定IP地址的指定端口号
            client = new Socket(inetAddress,port);
            //获取该套接字的输出流
            outputStream = client.getOutputStream();
            //创建Scanner套接字
            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNextLine()){
                String line = scanner.nextLine();//获取输入行数据
                //将数据写入输出流
                outputStream.write(line.getBytes(),0,line.getBytes().length);
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //关闭输出流
            if (outputStream!=null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //关闭客户端套接字
            if (client!=null){
                try {
                    client.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

}

TCP简单通信 — 文件上传

文件服务器
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class FileServer {

    public static void main(String[] args) {
        ServerSocket serverSocket = null;//服务器套接字
        Socket socket = null;//套接字
        InputStream inputStream = null;//输入流
        FileOutputStream fileOutputStream = null;//文件输出流
        OutputStream outputStream = null;//输出流
        try {
            serverSocket = new ServerSocket(8888);//创建绑定到指定端口的服务器套接字
            socket = serverSocket.accept();//侦听要连接到此套接字并接受它。 该方法将阻塞直到建立连接。
            inputStream = socket.getInputStream();//获取该套接字的输入流
            fileOutputStream = new FileOutputStream(new File("rec.jpg"));//创建文件输出流
            //读取输入流数据 并写入文件输出流
            byte[] buff = new byte[1024];
            int len = 0;
            while ((len = inputStream.read(buff)) != -1){
                fileOutputStream.write(buff,0,len);
            }

            //获取该套接字的输出流
            outputStream = socket.getOutputStream();
            outputStream.write("接收完毕,可以断开了".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (outputStream != null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileOutputStream != null){
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputStream != null){
                try {
                    inputStream.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();
                }
            }
        }

    }

}
文件客户端
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

public class FileClient {

    public static void main(String[] args) {
        Socket socket = null;
        FileInputStream fileInputStream = null;
        OutputStream outputStream = null;
        InputStream inputStream = null;
        try {
            InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
            int port = 8888;
            socket = new Socket(inetAddress,port);//创建流套接字并将其连接到指定IP地址的指定端口号
            outputStream = socket.getOutputStream();//获取该套接字的输出流
            fileInputStream = new FileInputStream(new File("Hydrangeas.jpg"));//创建文件输入流

            //读取文件输入流数据,并写入输出流
            byte[] buff = new byte[1024];
            int len = 0;
            while ((len = fileInputStream.read(buff)) != -1){
                outputStream.write(buff,0,len);
            }
            /*
             在客户端或者服务端通过socket.shutdownOutput()都是单向关闭的,即关闭客户端的输出流并不会关闭服务端的输出流,所以是一种单方向的关闭流;
             通过socket.shutdownOutput()关闭输出流,但socket仍然是连接状态,连接并未关闭
             如果直接关闭输入或者输出流,即:in.close()或者out.close(),会直接关闭socket
             */
            //通知服务器 我数据输出完毕
            socket.shutdownOutput();//关闭客户端输出流
            //获取该套接字的输入流
            inputStream = socket.getInputStream();
            len = 0;
            //接收并打印输入流数据
            while ((len = inputStream.read(buff)) != -1){
                String str = new String(buff,0,len);
                System.out.println(str);
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (inputStream != null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileInputStream != null){
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outputStream != null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

UDP简单通信

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

public class UdpSocket1 {
    public static void main(String[] args) {
        DatagramSocket datagramSocket = null;
        try {
            //DatagramSocket表示用于发送和接收数据报数据包的套接字。
             datagramSocket = new DatagramSocket(8888);
            String str = "我是UDP传输端1";
            //DatagramPacket表示数据报包,数据报包用于实现无连接分组传送服务。
            DatagramPacket datagramPacket = new DatagramPacket(str.getBytes(),0,str.getBytes().length, InetAddress.getByName("127.0.0.1"),9999);
            datagramSocket.send(datagramPacket);
            
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
        e.printStackTrace();
        }finally {
            if (datagramSocket != null){
                datagramSocket.close();
            }
        }
    }
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class UdpSocket2 {

    public static void main(String[] args) {
        DatagramSocket datagramSocket = null;
        try {
            //创建数据报套接字
            datagramSocket = new DatagramSocket(9999);
            //接收数据包
            byte[] buff = new byte[1024];
            DatagramPacket datagramPacket = new DatagramPacket(buff,0,buff.length);
            datagramSocket.receive(datagramPacket);//阻塞式接收

            System.out.println(datagramPacket.getAddress());
            System.out.println(datagramPacket.getPort());
            System.out.println(new String(datagramPacket.getData(),0,datagramPacket.getLength() ));

        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (datagramSocket != null){
                datagramSocket.close();
            }
        }

    }
}

UDP简单通信 — 聊天

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;

public class TalkSend implements Runnable {
    int partFrom = 0;//接收端 端口
    int partTo = 0;//发送到 端口
    String ipTo = null;//发送到ip

    public TalkSend(int partFrom,int partTo, String ipTo){
        this.ipTo = ipTo;
        this.partFrom = partFrom;
        this.partTo = partTo;
    }

    @Override
    public void run() {
        DatagramSocket datagramSocket = null;
        try {

            //DatagramSocket表示用于发送和接收数据报数据包的套接字。
            datagramSocket = new DatagramSocket(partFrom);
            Scanner scanner = new Scanner(System.in);

            while (scanner.hasNextLine()){
                String line = scanner.nextLine();
                DatagramPacket datagramPacket = new DatagramPacket(line.getBytes(),0,line.getBytes().length, InetAddress.getByName(ipTo),partTo);
                datagramSocket.send(datagramPacket);
            }
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (datagramSocket != null){
                datagramSocket.close();
            }
        }
    }

}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class TalkRec implements Runnable {

    int partFrom = 0;//接收端 端口


    public TalkRec(int partFrom){
        this.partFrom = partFrom;
    }

    @Override
    public void run() {
        DatagramSocket datagramSocket = null;
        try {
            //创建数据报套接字
            datagramSocket = new DatagramSocket(partFrom);
            while (true) {
                //接收数据包
                byte[] buff = new byte[1024];
                DatagramPacket datagramPacket = new DatagramPacket(buff, 0, buff.length);
                datagramSocket.receive(datagramPacket);//阻塞式接收
                System.out.println(datagramPacket.getAddress()+":"+datagramPacket.getPort()+" : "+new String(datagramPacket.getData(), 0, datagramPacket.getLength()));
            }
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (datagramSocket != null){
                datagramSocket.close();
            }
        }
    }
}
public class Talk1 {

    public static void main(String[] args) {

        new Thread(new TalkSend(7777,9999,"127.0.0.1")).start();
        new Thread(new TalkRec(8888)).start();

    }
}

public class Talk2 {
    public static void main(String[] args) {

        new Thread(new TalkSend(5555,8888,"127.0.0.1")).start();
        new Thread(new TalkRec(9999)).start();
    }
}

URL 统一资源定位符

用于定位资源。在WWW上,每一信息资源都有统一的且在网上唯一的地址,该地址就叫URL(Uniform Resource Locator,统一资源定位器),它是WWW的统一资源定位标志,就是指网络地址。

URL组成
协议://主机:端口/项目名/资源文件名
import java.net.MalformedURLException;
import java.net.URL;

public class URLTest {
    public static void main(String[] args) {
        try {
            URL url = new URL("https://editor.csdn.net/md?articleId=110088434");

            System.out.println(url.getPath());//文件名
            System.out.println(url.getHost());//主机名
            System.out.println(url.getProtocol());//协议
            System.out.println(url.getFile());//全路径
            System.out.println(url.getQuery());//参数 键值对
            System.out.println(url.getPort());//端口号

        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

    }
}
URL下载网络资源
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class UrlDownload {
    public static void main(String[] args) {
        InputStream in = null;
        FileOutputStream fileOutputStream = null;
        try {
            URL url = new URL("https://m701.music.126.net/20201125215637/9b70b42b383bf399d5a7d3f2aee8b941/jdyyaac/obj/w5rDlsOJwrLDjj7CmsOj/4903215562/5bfc/fbd2/fa38/adfd6bf3d0fb529fb2681943d6065842.m4a");
            URLConnection urlConnection = url.openConnection();
            in = urlConnection.getInputStream();
            fileOutputStream = new FileOutputStream(new File("5842.m4a"));
            byte[] buff = new byte[1024];
            int len = 0;
            while ((len = in.read(buff)) != -1){
                fileOutputStream.write(buff,0,len);
            }

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

        }


    }
}

你可能感兴趣的:(JAVA杂记,网络编程,tcpip,UDP,三次握手,四次挥手)