网络编程:基本概念&udp

1.  OSI 模型

        OSI 模型  ===》开放系统互联模型  ==》分为7层:
    理想模型  ==》尚未实现
        tftp 
        b  /etc/passwd 
        a /etc/123
        应用层  
        表示层  加密解密  gzip
        会话层  网络断开,连接状态,keep-close keep-alive

        传输层tcp  udp  协议  文件    视频,音频
        网路层ip   NAT

        链路层  交换机  数据的格式化  帧 校验
        物理层         100Mb/8  Gbits   100MB 同轴电缆 10Gb    2.4G 5G

从下往上,下最基础 

2. TCP/IP模型

        TCP/IP模型  ==》网际互联模型   ==》分为4层:
       实用模型  ===》工业标准
      tcp/ip协议栈
        应用层   ====》应用程序
        传输层   ====》端口号tcp udp(使用哪种方式传输,tcp可靠udp实时性高
        网络层   ====》IP 地址(如何找到对方、主机
        接口层   ====》网卡 驱动  1GB
pcap ,,,

3. TCP/IP协议族

    www.taobao.com ---> 192.168.0.19
    www.voa.com vpn  
    DNS 域名解析(一般以省为单位)


    DHCP(动态主机配置协议)
    应用层: HTTP(网页) TFTP(简单近距离传输文件) FTP(互联网远距离传输)
                   SNMP(管理和监视网络设备、系统和应用程序)  DNS ...
    传输层: TCP  UDP   56k猫
    网络层: IP  ICMP(ping) RIP OSPF IGMP ...
    接口层: ARP(地址解析协议)  RARP  ...   ip--->mac  
    arp,,,,
    192.160.0.112 


一、 网络基础

网络基础 ===》A B C D E 类
010  3333344444
IP地址 == 网络位 + 主机位

IP地址的分类: 点分十进制   ipv4  712934
    A类:    超大规模性网络
                          8    8     8    8
        1.0.0.0 - 126.255.255.255  126.1.1.1 
         网络号                                 126.1.1.2
        255.0.0.0  (子网掩码)  
        私有:
        10.0.0.0 - 10.255.255.255
        127.0.0.1
    B类:    大中规模型网络
        128.0.0.0 - 191.255.255.255
        128.2.1.2  128.2.7.2
        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
        静态路由
        192.168.0.0
        192.168.0.1  网关gate
        192.168.0.255 (发广播,所有局域网的人都能收到)

    D类:    组播和广播
        224.0.0.0 - 239.255.255.255(群聊发,不面向所有人,不限局域网)
        192.168.0.255 ==  255.255.255.255(只能是局域网,一人发,所有人收)
        235.1.2.3
        192.168.1.0 
        192.168.0.1   网关
        192.168.1.255 广播 

    E类:    实验
        240.0.0.0 - 255.255.255.255
        
   C 类网络:
    ip地址的前三组是网络地址,第四组是主机地址。
    二进制的最高位必须是: 110xxxxx开头
    十进制表示范围: 192.0.0.0 -223.255.255.255
    默认网络掩码:   255.255.255.0
    网络个数: 2^24 个 约 209 万个
    主机个数: 2^8  个 254 个+2 ===》1 是网关 1是广播
    私有地址: 192.168.x.x 局域网地址。
  
  sudo vim  /etc/network/interfaces "配置网络"
  sudo /etc/init.d/networking restart      
  sudo reboot
    192.168.0.0
    192.168.0.1  route 
    192.168.0.255 boardcast
    801.n.g 
    单机上网的配置:
    1、有网络接口并插入网线。
    2、有ip地址
    3、配置网络设置
            ip(修改临时ip): ifconfig ethX X.X.X.X/24 up  ifconfig ens33 192.168.0.13/24(子网掩码) up  255.255.255.0
            网关: route add default gw x.x.x.x 
            DNS:  vi /etc/resolv.conf  ==>nameserver 8.8.8.8
            测试:ping www.baidu.com
            netstat  -anp(可以查看计算机的网络状态)

二、网络接口

        1. socket  套接字(文件描述符——关联网络设备) ==》BSD socket ==》用于网络通信的一组接口函数。socket api   application interface函数接口
        2. ip+port 地址+端口===》地址用来识别主机
                                                  端口用来识别应用程序

          port 分为 TCP port / UDP port  范围都是: 1-65535
          约定1000 以内的端口为系统使用。
            http 80   www.baidu.com
                3306
                telnet 21 
                ssh 22

三、网络字节序 

        大端存储(低位在高内存——网络设备)
        小端   0x12345678(低位在低内存——主机)
        12 00   
        00 12
        192.168.0.12(大端)“最高位 存储在 最前面”
        12.0.168.192(小端)

四、UDP(用户数据报)

1、特性: 无链接  不可靠  大数据   

2、框架: C/S模式 

   server:socket() ===>bind()===>recvfrom()===>close()
   client:socket() ===>bind()===>sendto() ===>close()

        注意:socket()的参数需要调整。

      socket(PF_INET,SOCK_DGRAM,0);

      bind() 客户端(c)是可选的服务器端(s)是必选的

1.socket 

int socket(int domain, int type, int protocol);
功能:程序向内核提出创建一个基于内存的套接字描述符

参数:domain  地址族,PF_INET == AF_INET ==>互联网程序
                                       PF_UNIX == AF_UNIX ==>单机程序

           type    套接字类型:
                                SOCK_STREAM  流式套接字 ===》TCP   
                                SOCK_DGRAM   用户数据报套接字===>UDP
                                SOCK_RAW     原始套接字  ===》IP

           protocol 协议 ==》0 表示自动适应应用层协议。

返回值:成功 返回申请的套接字id
              失败  -1;

 2.bind

        int bind(int sockfd, struct sockaddr *my_addrsocklen_t addrlen);
功能:如果该函数在服务器端调用,则表示将 参数1相关的文件描述符文件 与参数2指定的接口地址关联,用于从该接口接受数据

           如果该函数在客户端调用,则表示要将 数据从参数1所在的描述符中 取出 并从 参数2所在的接口设备上 发送出去

注意:如果是客户端,则该函数可以省略,由默认接口发送数据。
参数:sockfd 之前通过socket函数创建的文件描述符,套接字id
           my_addr 是物理接口的结构体指针。表示该接口的信息

      struct sockaddr      通用地址结构
      {
          u_short sa_family;  地址族
          char sa_data[14];   地址信息
      };

      转换成网络地址结构如下:
      struct _sockaddr_in    ///网络地址结构
      {
          u_short           sin_family; 地址族
          u_short           sin_port;   ///地址端口
          struct in_addr  sin_addr;   ///地址IP
          char               sin_zero[8]; 占位
      };

      struct in_addr
      {
          in_addr_t s_addr;
      }

      socklen_t addrlen: 参数2 的长度。
返回值:成功  0 
              失败  -1; 

3.发送接收函数:

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                       
const struct sockaddr *dest_addr, socklen_t addrlen);

功能:用于UDP协议中向对方发送数据
参数:sockfd  本地的套接字id
           buff    本地的数据存储,一般是要发送的数据
           len     要发送的数据长度
           flags   要发送数据方式,0 表示阻塞发送

          dest_addr: 必选,表示要发送到的目标主机信息结构体
          addrlen :目标地址长度

返回值:成功  发送的数据长度
              失败   -1;


ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                          
struct sockaddr *src_addr, socklen_t *addrlen);

功能:用于UDP协议中获取对方发送的数据。
参数:sockfd 本地的套接字id
           buff   要存储数据的内存区,一般是数组或者动态内存
           len    要获取的数据长度,一般是buff的大小
           flags  获取方式,0 阻塞

           src_addr 可选,表示对方的地址信息结构体,如果为NULL,表示不关心对方地址
           addrlen  对方地址信息结构体大小,如果对方地址NULL,则该值也为NULL
返回值:成功 接收到的数据长度
              失败  -1;

4.关闭

close()  ===>关闭指定的套接字id; 


注意

1.数据与数据有边界
2.收发次数要对应
3.recvfrom 会阻塞
4.sento 不会阻塞(recvfrom不收,不影响sento发) 


   c找s

server.c 

#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <string.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>   
#include <arpa/inet.h>  
#include <time.h>  
 
typedef struct sockaddr *SA;  
  
int main(int argc, char *argv[])  
{  
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 创建一个UDP套接字  
    if(-1 == sockfd) // 检查socket调用是否失败  
    {  
        perror("socket"); // 打印错误信息  
        exit(1); // 退出程序  
    }  
  
    // 定义服务器地址和客户端地址结构体(尽管客户端地址通常在recvfrom中填充)  
    struct sockaddr_in ser, cli;  
    bzero(&ser, sizeof(ser)); // 初始化服务器地址结构体  
    bzero(&cli, sizeof(cli)); // 初始化客户端地址结构体(但这里实际上不需要提前初始化)  
  
    // 设置服务器地址结构体  
    ser.sin_family = AF_INET;  
    ser.sin_port = htons(50000); // 端口号转换为网络字节序  
    ser.sin_addr.s_addr = inet_addr("192.168.203.128"); // 服务器IP地址  
  
    // 将套接字绑定到服务器地址和端口  
    int ret = bind(sockfd, (SA)&ser, sizeof(ser));  
    if(-1 == ret)  
    {  
        perror("bind"); // 绑定失败时打印错误信息  
        exit(1); // 退出程序  
    }  
  
    socklen_t len = sizeof(cli); // 用于recvfrom的客户端地址长度  
  
    // 无限循环接收数据并发送响应  
    while(1)  
    {  
        char buf[512] = {0}; // 准备接收数据的缓冲区  
        // 接收数据,注意这里&len是必需的,因为recvfrom会修改它以反映实际接收到的客户端地址长度  
        recvfrom(sockfd, buf, sizeof(buf), 0, (SA)&cli, &len);  
  
        time_t tm;  
        time(&tm); // 获取当前时间  
  
        // 这里有一个问题:buf被用于接收数据,然后又被用于存储新的字符串(包括原始数据和时间戳)  
        // 这会导致原始数据被覆盖。应该使用另一个缓冲区来存储最终的发送数据  
        sprintf(buf, "%s %s", buf, ctime(&tm)); // 将时间戳附加到接收到的数据上  
  
        // 发送数据回客户端,但注意len在这里已经被recvfrom修改,表示客户端地址的长度  
        // 对于sendto,我们应该使用sizeof(cli)或重新初始化len  
        sendto(sockfd, buf, strlen(buf), 0, (SA)&cli, len); // 这里使用len可能不是最佳实践  
    }  
  
    // 注意:由于程序进入了一个无限循环,下面的close和return语句实际上永远不会被执行  
    close(sockfd); // 正常情况下应该关闭套接字  
    return 0; // 程序正常结束  
}

client.c

#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <string.h>  
#include <sys/types.h>          /* See NOTES */  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <netinet/ip.h>  
#include <arpa/inet.h>  
#include <time.h>  
  
// 定义一个类型别名SA,指向sockaddr结构体  
typedef struct sockaddr *SA;  
// 注意:它尝试定义一个函数指针类型而不是简单的结构体指针。  

  
int main(int argc, char *argv[])  
{  
    // 创建一个UDP套接字  
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);  
    if(-1 == sockfd)  
    {  
        perror("socket"); // 如果创建套接字失败,打印错误信息  
        exit(1); // 退出程序  
    }  
  
    // 初始化sockaddr_in结构体,用于指定服务器地址和端口  
    struct sockaddr_in ser;  
    bzero(&ser, sizeof(ser)); // 将结构体内存清零  
    ser.sin_family = AF_INET; // 使用IPv4地址  
    // 将端口号从主机字节序转换为网络字节序  
    ser.sin_port = htons(50000);  
    // 将点分十进制的IP地址字符串转换为网络字节序的整数  
    ser.sin_addr.s_addr = inet_addr("192.168.203.128");  
  
    // 无限循环,发送数据并尝试接收响应  
    while(1)  
    {  
        char buf[512] = "hello,this is udp test"; // 准备发送的数据  
        // 发送数据到指定的服务器地址和端口  
        sendto(sockfd, buf, strlen(buf), 0, (SA)&ser, sizeof(ser));  
          
        // 清空缓冲区,准备接收数据  
        bzero(buf, sizeof(buf));  
        // 尝试接收数据,但源地址和端口被设置为NULL,这通常是不正确的  
        // 在实际应用中,应该提供一个sockaddr_in结构体来接收源地址和端口信息  
        recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL);  
          
        // 打印接收到的数据(但在这个例子中,由于recvfrom的源地址和端口被设置为NULL,它可能不会按预期工作)  
        printf("buf is %s\n", buf);  
          
        // 等待1秒后再发送下一个数据包  
        sleep(1);  
    }  
  
    // 注意:由于程序进入了一个无限循环,下面的close和return语句实际上永远不会被执行  
    close(sockfd); // 关闭套接字  
    return 0; // 程序正常结束  
}

  • 23
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值