IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 网络编程与HTTP协议 -> 正文阅读

[网络协议]网络编程与HTTP协议

一、计算机网络基础

1. 网络

  • 网络:由若干结点和连接这些结点的链路组成,网络中的结点可以是计算机,交换机、路由器等设备。
    网络设备有:交换机、路由器、集线器
    传输介质有:双绞线、同轴电缆、光纤

  • 互联网:把多个网络连接起来就构成了互联网。目前最大的互联网就是我们常说的因特网。

  • IP地址
    IP 地址就是给因特网上的每一个主机(或路由器)的每一个接口分配的一个在全世界范围内唯一的标识符。IP 地址因其特殊的结构使我们可以在因特网上很方便地进行寻址。
    IP 地址有分 IPV4 和 IPV6 两种类别格式,IPV4 是类似”A.B.C.D”的格式,它是 32 位的,用“.”分成四个段,每个段是 8 个位(值为 0-255),用 10 进制表示。IPV6 地址是 128位。
    在这里插入图片描述

  • MAC地址
    在局域网中,硬件地址又称为物理地址或者 MAC 地址,长度 48 位,是固化在计算机适配器的 ROM 中的地址。

    MAC和IP都可唯一标识一台主机,为什么有了MAC还需要IP呢?
    (1)IP便于寻址;
    (2)IP可表示在网络中地变化,而MAC不能。比如当我们把一个笔记本从一个城市带到另一个城市时,虽然地理位置改变了,但是电脑在局域网中的“地址”仍然不变。所以在网络上方便寻找某个主机,还得需要IP地址来完成。

  • 端口号
    在一台主机上用来唯一标识一个应用程序(进程)。
    在这里插入图片描述

2. 网络分层模型

在这里插入图片描述
网络分层的好处:
在这里插入图片描述

二、Socket网络编程

1. TCP编程流程

在这里插入图片描述
listen的作用:
在这里插入图片描述
四次挥手也可以演化成三次(二三步和一起)
在这里插入图片描述

TCP服务器端代码ser.c

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

int main()
{
  int sockfd=socket(AF_INET,SOCK_STREAM,0);//创建监听套接字
  assert(sockfd!=-1);
  struct sockaddr_in saddr,caddr;//套接字地址。服务器端Ip,port;客户端ip,port
  memset(&saddr,0,sizeof(saddr));
  saddr.sin_family=AF_INET;
  saddr.sin_port=htons(6000);//1024以内的为知名端口,4096以内的为保留端口,大于4096的为临时端口
  saddr.sin_addr.s_addr=inet_addr("127.0.0.1");//指定ip地址,这里用回环序列进行测试,inet_addr将字符串转成无符号整形
  int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//地址绑定,为套接字指定一个ip+port,即地址
  assert(res!=-1);
  res=listen(sockfd,5);//监听端口,5在linux系统上指的是监听已完成三次握手的监听队列的大小
  while(1)//服务器循环接收客户端连接
  {
    int len=sizeof(caddr);
    int c=accept(sockfd,(struct sockaddr*)&caddr,&len);//c是连接套接字,接受连接,可能阻塞
    if(c<0)
    {
      perror("accept error");
      continue;
    }
    printf("c=%d\n",c);
    while(1)
    {
      char buff[128]={0};
      int n=recv(c,buff,127,0);//recv返回值为0,说明对端关闭了
      if(n<=0)
      {
        break;
      }
      printf("buff(%d)=%s",n,buff);
      send(c,"0k",2,0);
    }
    printf("one client over!\n");
    close(c);//四次挥手
  }
  return 0;
}

TCP客户端代码cli.c

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

int main()
{
  int sockfd=socket(AF_INET,SOCK_STREAM,0);
  assert(sockfd!=-1);
  //bind可绑定,但一般不绑定

  struct sockaddr_in saddr;
  memset(&saddr,0,sizeof(saddr));
  saddr.sin_family=AF_INET;
  saddr.sin_port=htons(6000);
  saddr.sin_addr.s_addr=inet_addr("127.0.0.1");

  int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//三次握手,建立连接
  assert(res!=-1);

  while(1)
  {
    char buff[128]={0};
    printf("input:\n");
    fgets(buff,128,stdin);
    if(strncmp(buff,"end",3)==0)
    {
      break;
    }
    send(sockfd,buff,strlen(buff),0);
    memset(buff,0,sizeof(buff));
    recv(sockfd,buff,127,0);
    printf("buff=%s\n",buff);
  }
  close(sockfd);//四次挥手

}

在这里插入图片描述

2. TCP协议特点

在这里插入图片描述
在这里插入图片描述

  • TCP和UDP的区别:
    TCP:面向连接、可靠的、字节流服务。使用 TCP 协议通信的双发必须先建立连接,然后才能开始数据的读写。双方都必须为该连接分配必要的内核资源,以管理连接的状态和连接上数据的传输。TCP 连接是全双工的,双方的数据可以通过一个连接进行读写。完成数据交换之后,通信双方都必须断开连接以释放系统资源。
    UDP:无连接、不可靠、数据报服务。发送端应用程序每执行一次写操作,UDP 模块就将其封装成一个 UDP 数据报发送。接收端必须及时针对每一个 UDP 数据报执行读操作,否则就会丢包。并且,如果用户没有指定足够的应用程序缓冲区来读取 UDP 数据,则 UDP 数据将被截断

  • TCP字节流服务
    在这里插入图片描述

  • 什么是粘包?怎么解决?
    在这里插入图片描述
    法一:发一次收一次
    在这里插入图片描述
    法二:每次先发数据的长度,再开始发数据,保证一次把这次数据收完

  • TCP的状态转移图

    为什么四次挥手都完成了还要停留到TIME_WAIT状态,持续大约两个报文的时间?(TIME_WAIT状态存在的意义?)
    TIME_WAIT存在于主动关闭的一方。
    (1)可靠地终止与TCP连接
    (2)保证让迟来的TCP报文段有足够的时间被识别丢弃。

  • 拥塞控制方法
    慢启动和拥塞避免
    快速重传和快速恢复
    在这里插入图片描述

2. 多进程、多线程处理并发

在这里插入图片描述

ser.c

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<signal.h>

int main()
{
  signal(SIGCHLD,SIG_IGN);
  int sockfd=socket(AF_INET,SOCK_STREAM,0);//创建监听套接字
  assert(sockfd!=-1);
  struct sockaddr_in saddr;//套接字地址。服务器端Ip,port;客户端ip,port
  memset(&saddr,0,sizeof(saddr));
  saddr.sin_family=AF_INET;
  saddr.sin_port=htons(6000);//1024以内的为知名端口,4096以内的为保留端口,大于4096的为临时端口
  saddr.sin_addr.s_addr=inet_addr("127.0.0.1");//指定ip地址,这里用回环序列进行测试,inet_addr将字符串转成无符号整形
  int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//地址绑定,为套接字指定一个ip+port,即地址
  assert(res!=-1);
  res=listen(sockfd,5);//监听端口,5在linux系统上指的是监听已完成三次握手的监听队列的大小
  while(1)//服务器循环接收客户端连接
  {
    struct sockaddr_in caddr;//存放客户端地址
    int len=sizeof(caddr);
    int c=accept(sockfd,(struct sockaddr*)&caddr,&len);//c是连接套接字,接受连接,可能阻塞
    if(c<0)
    {
      perror("accept error");
      continue;
    }
    pid_t pid=fork();
    if(pid==-1)
    {
      close(c);
      continue;
    }
    if(pid==0)
    {
      while(1)
      {
        char buff[128]={0};
        int n=recv(c,buff,127,0);//recv返回值为0,说明对端关闭了
        if(n<=0)
        {
          break;
        }
        printf("buff(%d)=%s",n,buff);
        send(c,"0k",2,0);
      }
      close(c);//子进程关闭
      printf("client over!\n");
      exit(0);
    }
    close(c);//父进程关闭
  }
}

3. UDP编程流程

UDP 提供的是无连接、不可靠的、数据报服务.
在这里插入图片描述
udpser.c

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

int main()
{
    int sockfd=socket(AF_INET,SOCK_DGRAM,0);//数据报服务的套接字
    assert(sockfd!=-1);

    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(6000);
    saddr.sin_addr.s_addr=inet_addr("127.0.0.1");

    int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    assert(res!=-1);

    while(1)
    {
        struct sockaddr_in caddr;
        int len=sizeof(caddr);
        char buff[128]={0};

        int n=recvfrom(sockfd,buff,127,0,(struct sockaddr*)&caddr,&len);
        printf("recv(%d):%s\n",n,buff);

        sendto(sockfd,"ok",2,0,(struct sockaddr*)&caddr,sizeof(caddr));
    }
}

udpcli.c,客户端的地址系统随机分配

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

int main()
{
    int sockfd=socket(AF_INET,SOCK_DGRAM,0);
    assert(sockfd!=-1);

    struct sockaddr_in saddr;//代表服务端的地址:IP port
    memset(&saddr,0,sizeof(saddr));

    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(6000);//指定服务器的端口
    saddr.sin_addr.s_addr=inet_addr("127.0.0.1");//指定服务器的ip
    while(1)
    {
        char buff[128]={0};
        printf("input:\n");
        fgets(buff,128,stdin);

        if(strncmp(buff,"end",3)==0)
        {
            break;
        }
        sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&saddr,sizeof(saddr));
        memset(buff,0,128);
        int len=sizeof(saddr);
        recvfrom(sockfd,buff,127,0,(struct sockaddr*)&saddr,&len);
        printf("buff=%s\n",buff);
    }
    close(sockfd);
}

在这里插入图片描述
UDP数据报服务,接收时要一次性接收完
在这里插入图片描述

三、HTTP协议与Web服务器

1. 浏览器与服务器通信过程

在这里插入图片描述

2. HTTP请求报文头

在这里插入图片描述

3. HTTP应答报文头

在这里插入图片描述

4. HTTP的应答状态

在这里插入图片描述
在这里插入图片描述

5. Web服务器的C语言实现

myhttp.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<assert.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<fcntl.h>

int socket_init();

char* get_filename(char buff[])
{
    if(buff==NULL)
    {
        return NULL;
    }
    char* s=strtok(buff," ");
    if(s==NULL)
    {
        return NULL;
    }
    printf("请求的方法是:%s\n",s);
    s=strtok(NULL," ");
    if(s==NULL)
    {
        return NULL;
    }
    return s;
}
int main()
{
    int sockfd=socket_init();
    assert(sockfd!=-1);
    while(1)
    {
        struct sockaddr_in caddr;
        int len=sizeof(caddr);
        int c=accept(sockfd,(struct sockaddr*)&caddr,&len);
        if(c<0)
        {
            continue;
        }
        char recv_buff[512]={0};
        recv(c,recv_buff,511,0);//接收浏览器发送过来的数据
        printf("read:\n%s\n",recv_buff);
        
        char* filename=get_filename(recv_buff);//获取浏览器访问的文件名字
        if(filename==NULL)
        {
            send(c,"err",3,0);
            close(c);
            continue;
        }

        char path[128]={"/home/chenfan/code"};//拼接路径
        if(strcmp(filename,"/")==0)
        {
            strcat(path,"index.html");
        }
        else
        {
            strcat(path,filename);
        }
        int fd=open(path,O_RDONLY);//打开文件
        if(fd==-1)
        {
            send(c,"404",3,0);
            close(c);
            continue;
        }
        int filesize=lseek(fd,0,SEEK_END);//文件大小
        lseek(fd,0,SEEK_SET);

        char head_buff[512]={"HTTP/1.0 200 OK\r\n"};
        strcat(head_buff,"Server: myhttp\r\n");
        sprintf(head_buff+strlen(head_buff),"Content-Length:%d\r\n",filesize);
        
        strcat(head_buff,"\r\n");

        send(c,head_buff,strlen(head_buff),0);//发送头部
        printf("send:%s\n",head_buff);

        char data_buff[1024]={0};
        int num=0;
        while((num=read(fd,data_buff,1024))>0)
        {
            send(c,data_buff,1024,0);
        }
        close(c);
    }
}
int socket_init()
{
    int sockfd=socket(AF_INET,SOCK_STREAM,0);
    if(sockfd==-1)
    {
        return -1;
    }
    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(80);
    saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
    int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(res==-1)
    {
        return -1;
    }
    res=listen(sockfd,5);
    if(res==-1)
    {
        return -1;
    }
    return sockfd;
}

index.html

<html>
  <head>
      <meta charset=utf-8>
      <title>主页</title>
    </head>  
      <body background=1.png>
          <a href="/next.html">下一页</a><br>
          <a href="/www.baidu.com">链接百度</a>
          <center>
              <h1>送孟浩然之广陵</h1><br>
              故人西辞黄鹤楼,<br>
              烟花三月下扬州。<br>
              孤帆远影碧空尽,<br>
              唯见长江天际流。<br>
          </center>
      </body>
</html>


next.html

<html>
    <head>
        <meta charset=utf-8>
        <title>新页面</title>
    </head>
    <body background=2.png>
        <a href="/index.html">上一页</a>
    </body>
</html>
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-11-10 12:45:58  更:2021-11-10 12:48:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年7日历 -2024/7/1 21:06:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码