网络编程:OSI协议,TCP/IP协议,IP地址,UDP编程

目录

国际网络通信协议标准:

1.OSI协议:

2.TCP/IP协议模型:

[应用层 :](#应用层 :)

传输层:

[网络层: IPV4协议 IP地址](#网络层: IPV4协议 IP地址)

[IP地址的划分: 公有地址 私有地址](#IP地址的划分: 公有地址 私有地址)

MAC地址:

端口号:

UDP编程

1.套接字:

2.流程

3.函数接口

[(1) socket](#(1) socket)

(2)sendto

[(3) inet_addr](#(3) inet_addr)

[(4) htons](#(4) htons)

[(5) bind](#(5) bind)

(6)recvfrom

主机作为发送端

主机作为接收端


网络:

协议:通信双方约定的一套标准

国际网络通信协议标准:

1.OSI协议:

应用层 发送的数据内容

表示层 数据是否加密

会话层 是否建立会话连接

传输层 数据传输的方式

网络层 数据的路由

数据链路层 局域网内部通信

物理层 物理介质的连接

2.TCP/IP协议模型:

应用层 发送的数据内容

传输层 数据传输的方式

网络层 数据由一台主机到达另一台主机

网络接口层 物理介质连接

应用层 :

FTP 文件传输协议

TFTP 简单文件传输协议

HTTP 超文本传输协议

HTTPS 安全超文本传输协议

SMTP 简单邮件传输协议

TELNET 网络终端登录协议

DNS 域名系统

..

传输层:

TCP 传输控制协议

UDP 用户数据报协议

UDP:不安全、不可靠的传输方式

UDP机制简单

UDP占用的资源开销比较小

TCP:安全、可靠的传输方式

TCP机制复杂

TCP占用的资源开销比较大

三次握手建立连接,确认双方能够通信

通信过程中保障数据传输的完整性

四次挥手断开连接,确保数据传输的完整

网络层:

IPV4协议
IP地址

管理员IP地址形式:192.168.0.167

内存IP地址形式: 11000000.10101000.00000000.10100111

IP地址 = 网络位 + 主机位

网络位:IP地址所属的网段(局域网的编号)

主机位:局域网中的第几台主机

网段号:网络位不变,主机位全为0

广播号:网络位不变, 主机位全为1

子网掩码:每个IP地址都会搭配一个子网掩码,用来区分IP地址的网络位及主机位

子网掩码展开成二进制,1对应的部分就是IP地址的网络位,0对应的部分就是IP地址的主机位

192.168.0.167

255.255.255.0

11000000.10101000.00000000.10100111

11111111.11111111.11111111.00000000

网段号192.168.0.0

广播号192.168.0.255

IP地址的划分:

公有地址
私有地址

A类:1.0.0.0 ~ 126.255.255.255

子网掩码:255.0.0.0

管理超大规模型网络

私有地址:10.0.0.0 ~ 10.255.255.255

B类:128.0.0.0 ~ 191.255.255.255

子网掩码:255.255.0.0

管理大中规模型网络

私有地址:172.16.0.0 - 172.31.255.255

C类:192.0.0.0 ~ 223.255.255.255

子网掩码:255.255.255.0

管理中小规模型网络

私有地址:192.168.0.0 ~ 192.168.255.255

D类:224.0.0.0 ~ 239.255.255.255

用于组播:255.255.255.0

E类:240.0.0.0 ~ 255.255.255.255

用于实验和研究:255.255.255.0

MAC地址:

设备自带网卡的地址(该地址是唯一的)

端口号:

找到同一台主机不同的应用程序

UDP编程

1.套接字:

实现Linux系统下的网络通信

套接字:一次通信对象的抽象

2.流程

发送端流程:1.创建套接字

2.发送信息

3.关闭套接字

接收端流程: 1.创建套接字

2.绑定IP和Port

3.接收信息

4.关闭套接字

3.函数接口

(1) socket

socket

int socket(int domain, int type, int protocol);

功能:

创建套接字

参数:

domain: AF_INET 表示IPV4协议

type:套接字类型

SOCK_STREAM:流式套接字

SOCK_DGRAM:数据报套接字

SOCK_RAW:原始套接字

protocol:

TCP和UDP协议:0

返回值:

成功返回用来通信的文件描述符

失败返回-1

(2)sendto

sendto

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,

const struct sockaddr *dest_addr, socklen_t addrlen);

功能:

发送信息

参数:

sockfd:套接字文件描述符

buf:发送数据空间首地址

len:发送数据长度

flags:发送属性 默认为0

dest_addr:目标地址存放空间首地址

addrlen:目的地址的长度

struct sockaddr_in {

sa_family_t sin_family; /* address family: AF_INET */

in_port_t sin_port; /* port in network byte order */

struct in_addr sin_addr; /* internet address */

};

/* Internet address. */

struct in_addr {

uint32_t s_addr; /* address in network byte order */

};

返回值:

成功返回发送字节数

失败返回-1

如果sendto对应的套接字没有绑定端口,则sendto绑定一个随机端口完成发送功能

(3) inet_addr

inet_addr

in_addr_t inet_addr(const char *cp);

功能:

将字符串的IP地址转换为32位的地址类型

(4) htons

htons

uint16_t htons(uint16_t hostshort);

功能:

将本地字节序(小端)转换成网络大端字节序

(5) bind

bind

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

功能:

将套接字与IP地址和端口进行绑定

参数:

addr:绑定地址结构体空间首地址

addrlen:绑定地址空间大小

返回值:

成功返回0

失败返回-1

注意:

只能绑定自己的IP地址

(6)recvfrom

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,

struct sockaddr *src_addr, socklen_t *addrlen);

功能:

接收信息

参数:

sockfd:套接字文件描述符

buf:接收数据空间首地址

len:接收数据长度

flags:接收的属性 默认为0

src_addr:存放发送方地址空间的地址

addrlen: 要接收的发送方地址的长度

返回值:

成功返回实际接收字节数

失败返回-1

练习一:

主机作为发送端

#include "../head.h"
//主机作为发送方
int main()
{
    int sockfd=0;
    ssize_t nsize=0;
    struct sockaddr_in recvaddr;
    struct sockaddr_in sendaddr;
    //创建用来通信的套接字
    sockfd=socket(AF_INET,SOCK_DGRAM,0);//AF_INET:IPV4协议族,SOCK_DGRAM:UDP数据报套接字
    if(sockfd==-1)
    {
        perror("failed to socket");
        return -1;
    }
    //将发送端套接字与IP地址和端口号绑定
    sendaddr.sin_family=AF_INET;
    sendaddr.sin_port=htons(30000);
    sendaddr.sin_addr.s_addr=inet_addr("192.168.0.185");
    bind(sockfd,(struct sockaddr *)&sendaddr,sizeof(sendaddr));

    //为目的地址赋值
    recvaddr.sin_family=AF_INET;//协议族为IPV4
    recvaddr.sin_port=htons(8080);//端口号( htons() 将本地字节序(小端)转换为网络字节序(大端))(发送给wltszs4.3.29网络调试助手)
    recvaddr.sin_addr.s_addr=inet_addr("192.168.0.135");//IP地址( inet_addr() 将字符串类型转换为二进制地址类型)
    
    //向目的地址发送数据
    nsize=sendto(sockfd,"66666666666",12,0,(struct sockaddr *)&recvaddr,sizeof(recvaddr));//注意强制类型转换
    if(nsize==-1)
    {
        perror("failed to sendto");
        return 0;
    }
    printf("发送成功\n");
    //关闭套接字
    close(sockfd);
    return 0;
}

主机作为接收端

#include "../head.h"
int main()
{

    int sockfd=0;
    int ret=0;
    char tmpbuff[200]={0};
    ssize_t nsize=0;
    struct sockaddr_in recvaddr;
    //创建套接字
    sockfd=socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd==-1)
    {
        perror("failed to socket");
        return -1;
    }
    //将套接字和IP地址与端口号绑定
    recvaddr.sin_family=AF_INET;
    recvaddr.sin_port=htons(20000);
    recvaddr.sin_addr.s_addr=inet_addr("192.168.0.185");
    ret=bind(sockfd,(struct sockaddr *)&recvaddr,sizeof(recvaddr));

    if(ret==-1)
    {
        perror("failed to bind");
        return 0;
    }
    //接受数据
    nsize=recvfrom(sockfd,tmpbuff,sizeof(tmpbuff),0,NULL,NULL);
    if(nsize==-1)
    {
        perror("failed to recvfrom");
        return 0;
    }
    //打印数据
    printf("接收到字节数:%ld,内容为:%s\n",nsize,tmpbuff);
    //关闭套接字
    close(sockfd);
    return 0;
}

练习二:利用UDP编程发送文件

发送端send.c

#include "../head.h"
int main()
{
    int sockfd;
    int ret=0;
    FILE *fp=NULL;
    struct sockaddr_in recvaddr;
    char readbuff[1024]={0};
    size_t size=0;
    ssize_t nsize=0;

   //创建套接字
    sockfd=socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd==-1)
    {
        perror("failed to socket");
        return -1;
    }
    
    //为目的地址赋值
    recvaddr.sin_family=AF_INET;
    recvaddr.sin_port=htons(30000);
    recvaddr.sin_addr.s_addr=inet_addr("192.168.0.187");
    //输入要发送的文件名
    printf("请输入要发送的文件名:");
    fgets(readbuff,sizeof(readbuff),stdin);
    readbuff[strlen(readbuff)-1]='\0';
    //打开该文件
    fp=fopen(readbuff,"r");
    if(fp==NULL)
    {
        perror("failed to fopen send.txt");
        return -1;
    }
    
   //发送文件名
    nsize=sendto(sockfd,readbuff,strlen(readbuff)+1,0,(struct sockaddr *)&recvaddr,sizeof(recvaddr));
     if(nsize==-1)
    {
         perror("failed to sendto");
         return -1;
    }
//发送文件内容
while(1)
{
     size=fread(readbuff,1,sizeof(readbuff),fp);
     if(size<=0)
     {
        break;
     }
     nsize=sendto(sockfd,readbuff,size,0,(struct sockaddr *)&recvaddr,sizeof(recvaddr));
     if(nsize==-1)
    {
         perror("failed to sendto");
         return -1;
    }
}
//发送文件结尾关闭标志
    sprintf(readbuff,".quit");
    nsize=sendto(sockfd,readbuff,size,0,(struct sockaddr *)&recvaddr,sizeof(recvaddr));
     if(nsize==-1)
    {
         perror("failed to sendto");
         return -1;
    }
   //关闭套接字和文件
    close(sockfd);
    fclose(fp);
    return 0;  
   
}

接收文件端

#include "../head.h"
int main()
{
    int sockfd;
    int ret=0;
    FILE *fp=NULL;
    char filename[100]={0};
    char tmpbuff[1024]={0};
    struct sockaddr_in recvaddr;
    char readbuff[1024]={0};
    size_t size=0;
    ssize_t nsize=0;

   //创建套接字
    sockfd=socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd==-1)
    {
        perror("failed to socket");
        return -1;
    }
    
   //绑定接收IP地址和套接字,端口号
    recvaddr.sin_family=AF_INET;
    recvaddr.sin_port=htons(30000);
    recvaddr.sin_addr.s_addr=inet_addr("192.168.0.187");
    bind(sockfd,(struct sockaddr *)&recvaddr,sizeof(recvaddr));
   //接收文件名
    nsize=recvfrom(sockfd,filename,sizeof(filename),0,NULL,NULL);
    if(nsize==-1)
    {
        perror("failed to recvfrom");
        return -1;
    }
    //创建文件
     fp=fopen(filename,"w");
    if(fp==NULL)
    {
        perror("failed to fopen");
        return -1;
    }
    //接收文件内容
    while (1)
    {
         nsize=recvfrom(sockfd,tmpbuff,sizeof(tmpbuff),0,NULL,NULL);
         if(nsize==0)
        {
            
            break;
        }
        if(!strcmp(tmpbuff,".quit"))
        {
            break;
        }
        fwrite(tmpbuff,nsize,1,fp);
    }
    //关闭套接字和文件
    close(sockfd);
    fclose(fp);
    return 0;  
   
}

练习三:利用UDP编程实现聊天功能

1.(进程实现)

send.c

#include "../head.h"
int main()
{
    pid_t pid;
    struct sockaddr_in sendaddr;
    struct sockaddr_in recvaddr;
    char tmpbuff[100]={0};
    ssize_t size_send;
    ssize_t size_recv;
    int sockfd=0;
    sockfd=socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd==-1)
    {
        perror("failed to socket");
        return -1;
    }
    recvaddr.sin_family=AF_INET;
    recvaddr.sin_port=htons(30000);
    recvaddr.sin_addr.s_addr=inet_addr("192.168.0.187");

//第一次发送是为了建立连接,数据可随机发送,不打印
    size_send = sendto(sockfd,"hello",6,0,(struct sockaddr *)&recvaddr,sizeof(recvaddr));
    if(size_send==-1)
    {
        perror("failed to sendto");
        return -1;
    }
    pid=fork();
    if(pid==-1)
    {
        perror("failed to fork");
        return -1;
    }
    if(pid==0)
    {   

        while (1)
        {
                memset(tmpbuff,0,sizeof(tmpbuff));
                fgets(tmpbuff,sizeof(tmpbuff),stdin);
                tmpbuff[strlen(tmpbuff)-1]='\0';
              
                size_send=sendto(sockfd,tmpbuff,strlen(tmpbuff),0,(struct sockaddr *)&recvaddr,sizeof(recvaddr));
                if(size_send==-1)
                {
                    perror("failed to sendto");
                    return -1;
                }
               
                if(!strcmp(tmpbuff,".quit"))
                {
                    
                    break;
                }
               
        }
        kill(getppid(),SIGKILL);

    }
    else if(pid>0)
    {
        while(1)
        {
            memset(tmpbuff,0,sizeof(tmpbuff));
            size_recv = recvfrom(sockfd,tmpbuff,sizeof(tmpbuff),0,NULL,NULL);
            if(size_recv==-1)
            {
                perror("failed to recvfrom");
                return -1;
            }
            if(!strcmp(tmpbuff,".quit"))
            {
                
                break;
            }
            printf("RECV:%s\n",tmpbuff);
        }
        kill(pid,SIGKILL);
         
    }
    close(sockfd);
    return 0;

}

recv.c

#include "../head.h"
int main()
{
    pid_t pid;
    struct sockaddr_in sendaddr;
    struct sockaddr_in recvaddr;
    size_t size_send;
    size_t size_recv;
    char tmpbuff[100]={0};
    socklen_t addrlen=sizeof(sendaddr);
    int ret=0;
    int sockfd=0;
    sockfd=socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd==-1)
    {
        perror("failed to socket");
        return -1;
    }
    recvaddr.sin_family=AF_INET;
    recvaddr.sin_port=htons(30000);
    recvaddr.sin_addr.s_addr=inet_addr("192.168.0.187");
    ret=bind(sockfd,(struct sockaddr *)&recvaddr,sizeof(recvaddr));
    if(ret==-1)
    {
        perror("failed to bind");
        return -1;
    }
//第一次接收是为了建立连接,数据不打印
    size_recv = recvfrom(sockfd,tmpbuff,sizeof(tmpbuff),0,(struct sockaddr *)&sendaddr,&addrlen);
   
    if(size_recv==-1)
    {
        perror("failed to recvfrom");
        return -1;
    }

    pid=fork();
    if(pid==-1)
    {
        perror("failed to fork");
        return -1;
    }
    if(pid==0)
    {
        while(1)
        {
             memset(tmpbuff,0,sizeof(tmpbuff));
               size_recv = recvfrom(sockfd,tmpbuff,sizeof(tmpbuff),0,NULL,NULL);
             
            if(size_recv==-1)
            {
                perror("failed to sendto");
                return -1;
            }
            
            if(!strcmp(tmpbuff,".quit"))
            {
                
                break;
            }
            printf("RECV:%s\n",tmpbuff);
        }
     kill(getppid(),SIGKILL);
        
    }
    else if(pid>0)
    {
        while (1)
        {
            memset(tmpbuff,0,sizeof(tmpbuff));
            fgets(tmpbuff,sizeof(tmpbuff),stdin);
            tmpbuff[strlen(tmpbuff)-1]='\0';
            size_send=sendto(sockfd,tmpbuff,strlen(tmpbuff),0,(struct sockaddr *)&sendaddr,sizeof(sendaddr));
            if(size_send==-1)
            {
                perror("failed to sendto");
                return -1;
            }
            if(!strcmp(tmpbuff,".quit"))
            {
              
                break;
            }
           
        }
          kill(pid,SIGKILL);
        
    }
    close(sockfd);
    return 0;


}

2.(线程实现)

send.c

#include "../head.h"

int sockfd = 0;
pthread_t tid1;
pthread_t tid2;
struct sockaddr_in recvaddr;

void *thread1(void *arg)
{
    char tmpbuff[1024] = {0};
    ssize_t nsize = 0;

    while (1)
    {
        memset(tmpbuff, 0, sizeof(tmpbuff));
        fgets(tmpbuff, sizeof(tmpbuff), stdin);
        tmpbuff[strlen(tmpbuff)-1] = '\0';
        
        nsize = sendto(sockfd, tmpbuff, strlen(tmpbuff), 0, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
        if (-1 == nsize)
        {
            perror("fail to sendto");
            return NULL;
        }

        if (!strcmp(tmpbuff, ".quit"))
        {
            break;
        }
    }
    pthread_cancel(tid2);

    return NULL;
}

void *thread2(void *arg)
{  
    char tmpbuff[1024] = {0};
    ssize_t nsize = 0;

    while (1)
    {
        memset(tmpbuff, 0, sizeof(tmpbuff));
        nsize = recvfrom(sockfd, tmpbuff, sizeof(tmpbuff), 0, NULL, NULL);
        if (-1 == nsize)
        {
            perror("fail to recvfrom");
            return NULL;
        }

        if (!strcmp(tmpbuff, ".quit"))
        {
            break;
        }
        
        printf("RECV:%s\n", tmpbuff);
    }
    pthread_cancel(tid1);

    return NULL;
}

int main(void)
{
    //1.创建套接字
    char tmpbuff[1024] = {"hello"};
    ssize_t nsize = 0;

    recvaddr.sin_family = AF_INET;
    recvaddr.sin_port = htons(RECV_PORT);
    recvaddr.sin_addr.s_addr = inet_addr(RECV_IP);

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd)
    {
        perror("fail to socket");
        return -1;
    }

    //2.发送一次
    nsize = sendto(sockfd, tmpbuff, strlen(tmpbuff), 0, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
    if (-1 == nsize)
    {
        perror("fail to sendto");
        return -1;
    }

    //3.创建两个线程
    pthread_create(&tid1, NULL, thread1, NULL);
    pthread_create(&tid2, NULL, thread2, NULL);

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    close(sockfd);

    return 0;
}

recv.c

#include "../head.h"

int sockfd = 0;
pthread_t tid1;
pthread_t tid2;
struct sockaddr_in recvaddr;
struct sockaddr_in sendaddr;

void *thread1(void *arg)
{
    char tmpbuff[1024] = {0};
    ssize_t nsize = 0;

    while (1)
    {
        memset(tmpbuff, 0, sizeof(tmpbuff));
        fgets(tmpbuff, sizeof(tmpbuff), stdin);
        tmpbuff[strlen(tmpbuff)-1] = '\0';
        
        nsize = sendto(sockfd, tmpbuff, strlen(tmpbuff), 0, (struct sockaddr *)&sendaddr, sizeof(sendaddr));
        if (-1 == nsize)
        {
            perror("fail to sendto");
            return NULL;
        }

        if (!strcmp(tmpbuff, ".quit"))
        {
            break;
        }
    }
    pthread_cancel(tid2);

    return NULL;
}

void *thread2(void *arg)
{  
    char tmpbuff[1024] = {0};
    ssize_t nsize = 0;

    while (1)
    {
        memset(tmpbuff, 0, sizeof(tmpbuff));
        nsize = recvfrom(sockfd, tmpbuff, sizeof(tmpbuff), 0, NULL, NULL);
        if (-1 == nsize)
        {
            perror("fail to recvfrom");
            return NULL;
        }

        if (!strcmp(tmpbuff, ".quit"))
        {
            break;
        }
        
        printf("RECV:%s\n", tmpbuff);
    }
    pthread_cancel(tid1);

    return NULL;
}

int main(void)
{
    //1.创建套接字
    char tmpbuff[1024] = {"hello"};
    ssize_t nsize = 0;
    int ret = 0;
    socklen_t addrlen = sizeof(sendaddr);

    recvaddr.sin_family = AF_INET;
    recvaddr.sin_port = htons(RECV_PORT);
    recvaddr.sin_addr.s_addr = inet_addr(RECV_IP);

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd)
    {
        perror("fail to socket");
        return -1;
    }

    ret = bind(sockfd, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
    if (-1 == ret)
    {
        perror("fail to bind");
        return -1;
    }

    //2.接收一次
    nsize = recvfrom(sockfd, tmpbuff, sizeof(tmpbuff), 0, (struct sockaddr *)&sendaddr, &addrlen);
    if (-1 == nsize)
    {
        perror("fail to recvfrom");
        return -1;
    }

    //3.创建两个线程
    pthread_create(&tid1, NULL, thread1, NULL);
    pthread_create(&tid2, NULL, thread2, NULL);

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    close(sockfd);

    return 0;
}
相关推荐
dsywws1 小时前
Linux学习笔记之vim入门
linux·笔记·学习
幺零九零零2 小时前
【C++】socket套接字编程
linux·服务器·网络·c++
小林熬夜学编程3 小时前
【Linux系统编程】第四十一弹---线程深度解析:从地址空间到多线程实践
linux·c语言·开发语言·c++·算法
程思扬4 小时前
为什么Uptime+Kuma本地部署与远程使用是网站监控新选择?
linux·服务器·网络·经验分享·后端·网络协议·1024程序员节
ZachOn1y4 小时前
计算机网络:运输层 —— 运输层概述
网络·tcp/ip·计算机网络·运输层
sun0077004 小时前
拷贝 cp -rdp 和 cp -a
linux·运维·服务器
wowocpp4 小时前
ubuntu 22.04 server 安装 anaconda3
linux·运维·ubuntu
乡村农夫4 小时前
cuda 环境搭建
linux
tingting01195 小时前
Linux 普通用户禁用sudo su - 命令
linux·运维·服务器
WZF-Sang5 小时前
Linux—进程学习-01
linux·服务器·数据库·学习·操作系统·vim·进程