拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 JAVA 网络编程

JAVA 网络编程

白鹭 - 2022-02-13 1990 0 0

目录

一、网络通信协议

1、概述

2、为什么协议要分层?

3、对于参考模型的介绍

4、TCP网络传输的基本流程

二、网络编程套接字(socket)

1、UDP(面向资料报)

2、TCP(面向字节流)

三、应用层协议HPPT

1、URL

2、抓包(Fiddler)

3、HPPT的方法

4、状态码的详解

5、cookie和session的用法

6、基本实作http协议的代码

四、传输层协议TCP和UDP

1、UDP协议的理解

2、TCP传输协议

3、TCP的十个特性

4、TCP和UDP之间的对比

五、网络层传输协议IP

1、地址管理

2、网段划分

3、路由选择

六、数据链路层和应用层(以太网协议和DNS协议)

1、以太网协议

2、DNS协议


一、网络通信协议

1、概述

计算机网络是通过传输介质、通信设施和网络通信协议,把分散在不同地点的计算机设备互连起来的,实作资源共享和资料传输的系统,网络编程就是撰写程序使互联网的两个(或多个)设备(如计算机)之间进行资料传输,Java语言对网络编程提供了良好的支持,通过其提供的界面我们可以很方便地进行网络编程,

网络通信协议是网络编程中的关键,通信双方达成的一种共识,当通信双方都遵守这样的约定,才能正确传输信息,

2、为什么协议要分层?

面试常见:

1、对于一台主机来说,它的作业系统内核实作了从应用层到物理层
2、对于一台路由器来说,它实作了从网络层到物理层,
3、对于一台交换机来说,它实作了从数据链路层到物理层,
4、对于集线器来说,它实作的物理层,

4、TCP网络传输的基本流程

在这些基本操作中涉及到封装分用两个操作流程,

封装的意思就是给基于资料的基础上,在资料前加上协议报头,当资料由应用层传输到传输层时,传输层会在得到的资料基础上加上传输层协议报头, 当资料由传输层到达网络层时,会继续添加网络层协议报头,也就是我们常说的IP地址,当资料由网络层传输到数据链路层时会在资料前加上数据链路层协议报头,也就是常数的MAC地址,数据链路层将资料发送给物理层时,物理层就会将这个资料转化成光电信号,通过一些硬设备,例如网线,光纤,电磁波等传输出去,

分用的程序正好与封装相反,当物理层接收到对方发送过来的光电信号时,会将它决议成二进制的bit流,进一步得到数据链路层资料帧, 数据链路层决议资料帧,玻璃针头和针尾取出,其中的IP资料报交给网络层,网络层接收到刚才的网络层资料报,通过决议去掉网络层的协议报头,把资料交给传输层,传输层拿到传输层,资料报在进行决议,去掉传输层报头,最后将资料交给应用层,这时应用层就可以决议资料,分析出发送者是谁,接收者是谁显示到桌面上,

当发送者通过自己的主机将资料封装完成之后,会通过路由器广域网等发送到服务器,当服务器通过分用把资料拆开之后看到接收方的地址,然后服务器将资料重新封装之后,通过路由器广域网等途径发送到接收者的主机,然后接收者的主机一步一步的进行分佣,最终得到资料并且显示出来,

二、网络编程套接字(socket)

套接字(socket)是一组API,用来实作网络编程,一般是通过客户端(server)和服务器(cilent)实作的,

IP地址:用来识别互联网上一台主机的位置,

埠号:用来区分是主机上的那个应用,

在一次通信程序中涉及到五元组:源IP目的IP源埠目的埠协议型别

注意:

bufferedWriter中的write方法可能写到缓冲区中没有写入内核中,需要使用flush方法来进行重绘,

如果要多个客户端可以同时相应我们可以通过一个执行绪池来控制多个客户端,

三、应用层协议HPPT

hppt和hppts都是应用层协议,应用层协议大多都需要手动指定,hppt协议是基于TCP来实作的,

1、URL

当你打开一个网页的时候,会出现一个网址这个网址就是URL,

url中的服务器的ip来确定是哪一个服务器,

url中的埠号来确定是哪个行程,

url中的path来确定是哪个行程所管理的具体档案,

GET和POST的区别?

GET一般把资料放到url中去

Post一般把资料放到body中去

4、状态码的详解

5、cookie和session的用法

cookie可以将登录认证后的用户信息保存在本地浏览器上,当后面每次发送http请求时,都会附带上这个信息,就不需要每次都重新验证用户,

但是这样明文传输cookie可能会泄密在这个前提下我们引入session来保存资料

在服务器登录成功时,我们把用户保存到一个hash表中,同时生成一个key(sessionid),把sessionid写回到这个cookie中去,当后续访问时,只需要在通过sessionid访问服务器中就行了,

6、基本实作http协议的代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

public class HttpRequset {
    private String method;//方法
    private String url;//url
    private String version;//版本号
    //协议头
    private Map<String,String> headers=new HashMap<>();
    //url中和body中的内容放在这里
    private Map<String,String> parameters=new HashMap<>();
    //cookie中的类容决议
    private Map<String,String> cookies=new HashMap<>();

    private String body;//body

    //用工厂模式来写
    public static HttpRequset build(InputStream inputStream) throws IOException {
        HttpRequset requset=new HttpRequset();

        BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));

        //1、决议首行
        String firstline=bufferedReader.readLine();
        String[] fiestlines=firstline.split(" "); //第一行是通过空格来区分的
        requset.method=fiestlines[0];
        requset.url=fiestlines[1];
        requset.version=fiestlines[2];
        //2、将首行中的url中的元素提取出来
        int pre=requset.url.indexOf("?");//如果没有就回传-1
        if(pre!=-1){
            String qureyString=requset.url.substring(pre+1);
            parseKV(qureyString,requset.parameters);
        }
        //3、将headers中的内容决议出来
        String line="";
        while((line=bufferedReader.readLine())!=null && line.getBytes().length!=0){
            String[] lines=line.split(": ");
            requset.headers.put(lines[0],lines[1]);
        }
        //4、决议cookie中的内容
        String cookie=requset.headers.get("Cookie");
        if(cookie!=null){
            parseCookie(cookie,requset.cookies);
        }
        //5、body中的内容
        if("POST".equalsIgnoreCase(requset.method) || "PUT".equalsIgnoreCase(requset.method)){
            //我们首先要知道body的长度
            int length=Integer.parseInt(requset.headers.get("Content-Length"));
            //建立一个缓冲区
            char[] buffer=new char[length];
            int len=bufferedReader.read(buffer);
            requset.body=new String(buffer,0,len);

            parseKV(requset.body,requset.parameters);
        }

        return requset;
    }

    private static void parseCookie(String cookie, Map<String, String> cookies) {
        String[] line=cookie.split("; ");
        for(String s:line){
            String[] lines=s.split("=");
            cookies.put(lines[0],lines[1]);
        }
    }

    private static void parseKV(String qureyString, Map<String, String> parameters) {
        String[] line=qureyString.split("&");
        for (String s:line){
            String[] lines=s.split("=");
            parameters.put(lines[0],lines[1]);
        }
    }

    public String getMethod() {
        return method;
    }

    public String getUrl() {
        return url;
    }

    public String getVersion() {
        return version;
    }

    public String getBody() {
        return body;
    }

    public String getHeaders(String key){
        return headers.get(key);
    }

    public String getParameters(String key){
        return parameters.get(key);
    }

    public String getCooies(String key){
        return cookies.get(key);
    }
}
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.Map;

public class HttpResponse {
    private String version="HTTP/1.1";//版本号
    private int status;//验证信息
    private String message;//状态信息
    //header中的内容
    private Map<String,String> headers=new HashMap<>();
    //body中的内容
    private StringBuffer body=new StringBuffer();
    private OutputStream outputStream=null;
    //工厂模式
    public static HttpResponse build(OutputStream outputStream){
        HttpResponse response=new HttpResponse();
        response.outputStream=outputStream;
        return response;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public void setHeaders(String key,String value){
        this.headers.put(key,value);
    }

    public void setBody(String val){
        this.body.append(val);
    }

    public void fush() throws IOException {
        BufferedWriter bufferedWriter=new BufferedWriter(new OutputStreamWriter(outputStream));
        //写第一行
        bufferedWriter.write(version+" "+status+" "+message+"\n");
        //将档案信息放入header中写入
        headers.put("Content-Length",body.toString().getBytes().length+"");
        //将header中的类容写入
        for(Map.Entry<String,String> entry:headers.entrySet()){
            bufferedWriter.write(entry.getKey()+": "+entry.getValue()+"\n");
        }
        //
        bufferedWriter.write("\n");
        //将body中的资料放入
        bufferedWriter.write(body.toString());
        //将资料重绘
        bufferedWriter.flush();
    }
}
<html>
<head>
    <meta charset="utf-8">
</head>
<body>
<form method="post" action="/login">
    <div style="margin-bottom: 5px">
        <input type="text" name="username" placeholder="请输入姓名">
    </div>
    <div style="margin-bottom: 5px">
        <input type="text" name="password" placeholder="请输入密码">
    </div>
    <div>
        <input type="submit" value="登录">
    </div>
</form>
</body>
</html>
import Test05.HttpServerV3;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class HttpServerV4 {
    static class User{
        //保存的相关信息
        public String userName;
        public int age;
        public String school;
    }
    private ServerSocket socket=null;

    //我们通过session会话
    private Map<String,User> session=new HashMap<>();

    public HttpServerV4(int port) throws IOException {
        this.socket = new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("系统启动");
        ExecutorService executorService= Executors.newCachedThreadPool();
        while(true){
            Socket cliensocket=socket.accept();
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    process(cliensocket);
                }
            });
        }
    }

    private void process(Socket cliensocket) {
        try {
            //读取请求
            HttpResponse response=HttpResponse.build(cliensocket.getOutputStream());
            HttpRequset requset=HttpRequset.build(cliensocket.getInputStream());

            //response.setHeaders("Set-Cookie","YYX=qwe");
            //计算相应
            if("GET".equalsIgnoreCase(requset.getMethod())){
                doGet(requset,response);
            }else if("Post".equalsIgnoreCase(requset.getMethod())){
                doPost(requset,response);
            }else{
                response.setStatus(405);
                response.setMessage("Method Not Allowed");
            }
            //写入
            response.fush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                cliensocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void doPost(HttpRequset requset, HttpResponse response) {
        //2\
        if(requset.getUrl().startsWith("/login")){
            String user=requset.getParameters("username");
            String pass=requset.getParameters("password");
            /*System.out.println(user+":"+pass);*/
            if("yyx".equals(user) && "2001".equals(pass)){
                //通过

                response.setStatus(403);
                response.setMessage("Forbidden");
                //要写不然回传的不是utf-8的编码格式
                response.setHeaders("Content-Type","text/html; charset=utf-8");

                //response.setHeaders("Set-Cookie","userName=YYX");

                String sessionId= UUID.randomUUID().toString();
                User user01=new User();
                user01.userName="杨亚轩";
                user01.age=18;
                user01.school="武昌工学院";
                session.put(sessionId,user01);
                response.setHeaders("Set-Cookie","sessionId="+sessionId);

                response.setBody("<html>");
                response.setBody("验证成功!");
                response.setBody("</html>");
            }else {
                //没有通过
                response.setStatus(403);
                response.setMessage("Forbidden");
                //要写不然回传的不是utf-8的编码格式
                response.setHeaders("Content-Type","text/html; charset=utf-8");
                response.setBody("<html>");
                response.setBody("验证失败!");
                response.setBody("</html>");
            }
        }

    }

    private void doGet(HttpRequset requset, HttpResponse response) throws IOException {
        //1\
        if(requset.getUrl().startsWith("/index.html")){
            String sessionId=requset.getCooies("sessionId");
            User user=session.get(sessionId);
            if (sessionId==null || user==null) {
                //当前情况下用户没有登录
                response.setStatus(200);
                response.setMessage("OK");
                response.setHeaders("Content-Type","text/html; charset=utf-8");
                InputStream inputStream=HttpServerV3.class.getClassLoader().getResourceAsStream("index.html");
                BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));

                String str="";
                while((str=bufferedReader.readLine())!=null){
                    response.setBody(str+"\n");
                }
                bufferedReader.close();
            }else{
                //已经登录就不需要再登录的
                response.setStatus(200);
                response.setMessage("OK");
                response.setHeaders("Content-Type","text/html; charset=utf-8");
                response.setBody("<html>");
                response.setBody("该用户已经登录了");
                response.setBody("</html>");
            }
        }
    }

    public static void main(String[] args) throws IOException {
        HttpServerV4 httpServerV4=new HttpServerV4(9090);
        httpServerV4.start();
    }
}

一个行程可以bind多个埠号

但是一个埠号不能被多个行程bind

四、传输层协议TCP和UDP

1、UDP协议的理解

对于UDP来说它有三个非常重要的特性

1)无连接(不需要建立连接就可以通信)

2)不可靠(接收方是否接受到讯息发送方不知道)

3)面向资料报(以DatagramPacket为单位进行传输)

UDP的协议格式:

2、TCP传输协议

对于TCP来说它有三个非常重要的特性

1)有连接(需要建立连接就可以通信)

2)可靠(接收方是否接受到讯息发送方知道)

3)面向字节流

TCP的协议格式:

TCP的报头是变长(报头长度在4的基础上*4)

3、TCP的十个特性

1、确认应答(核心)

当主机a向主机B发送资料的时候,主机B会向主机a发送一种应答报文ack,当主机a接收到由主机B发来的ack时,那么就能确定主机a发送过去的资料被主机B接收,

当主机a发送的资料为1到100时,那么主机B回传的确认应答为101,接下来资料就要从101开始发送,

2、超时重传

确认应答是比较理想的情况,资料在传输程序中有很大的概率丢包,

当出现丢包状况时有两种可能,第1种就是主机a发送的请求丢失,第2种情况就是主机B发送的ack丢失,当发送一条资料后,TCP内部就会自动生成一个定时器,当一定的时间没有收到ack,那么就会触发定时器触发重传,如果是ack丢了,那么TCP会在内部进行资料去重,

3、连接管理

a)建立连接(三次握手)

标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *